笔记44-徐 事务隔离级别和锁的申请和释放

笔记44-徐 事务隔离级别和锁的申请和释放

  1 --事务隔离级别和锁的申请和释放
  2 
  3 --数据库有并发操作的时候,修改数据的事务会影响同时要去读取或修改相同数据的其他事务。
  4 --如果数据存储系统并没有并发控制,则事务可能会看到以下负面影响:
  5 --丢失更新
  6 --未提交的依赖关系(脏读)
  7 --不一致的分析(不可重复读)
  8 --幻读
  9 
 10 
 11 --上面4种情况的定义可以在SQL联机丛书里找到。当许多人试图同时修改数据库中的数据时,必须
 12 --实现一个控制系统,使一个人所做的修改不会对他人所做的修改产生负面影响,这就称为并发控制
 13 
 14 --需要注意的是,不同性质的应用程序对并发控制会有不一样的需求。例如一个银行ATM系统,可能
 15 --就不允许不可重复读的出现。而一个报表系统,可能对脏读的敏感度不会那么高。要防止的负面
 16 --影响越多,隔离级别就越高,程序的并发性也就越差。并不是每个应用程序都需要将上面4种问题
 17 --全部避免
 18 
 19 --数据库系统通过定义事务的隔离级别来定义使用哪一级的并发控制。SQL-99标准定义了下列隔离
 20 --级别,SQL数据库引擎支持所有这些隔离级别:
 21 --未提交读(隔离事务的最低级别,只能保证不读取物理上损坏的数据)
 22 --已提交读(数据库引擎的默认级别,可以防止脏读)
 23 --可重复读
 24 --可序列化(隔离事务的最高级别,可防止幻影,事务之间完全隔离)
 25 
 26 
 27 --表 :不同隔离级别允许的并发副作用
 28 --隔离级别               脏读            不可重复读                       幻读
 29 --未提交读                否                 是                            是
 30 --相当于所有select语句加上nolock提示
 31 --已提交读                否                 是                            是
 32 --可重复读                否                 否                            是
 33 --可序列化                否                 否                            否
 34 
 35 
 36 --未提交读(read uncommitted)
 37 --指定语句可以读取已由其他事务修改但尚未提交的行。也就是说,允许脏读
 38 --在read uncommitted级别运行的事务,不会发出共享锁来防止其他事务修改当前事务读取
 39 --的数据。read committed事务也不会被排他锁阻塞。共享锁会禁止当前事务读取其他事务已
 40 --修改但尚未提交的行。设置此选项后,此事务可以读取其他事务未提交的修改。在事务
 41 --结束之前,其他事务可以更改数据中的值。该选项的作用与在事务内所有select语句中
 42 --的所有表上设置nolock相同。这是隔离级别中限制最少的级别。
 43 --换句话说,未提交读的意思也就是:读的时候不申请共享锁。所以他不会被其他人的排他锁
 44 --阻塞,他也不会阻塞别人申请排他锁
 45 
 46 
 47 --已提交读(read committed)
 48 --指定语句不能读取已由其他事务修改但尚未提交的数据.这样可以避免脏读。其他事务可以在
 49 --当前事务的各个语句之间更改数据,从而产生不可重复读取数据和幻象数据。该选项是
 50 --SQL的默认设置
 51 --数据库引擎会在读的时候使用共享锁防止其他事务在当前事务执行读取操作期间修改行。
 52 --共享锁还会阻止语句在其他事务完成之前读取由这些事务修改的行。但是,语句运行
 53 --完毕后便会释放共享锁,而不是等到事务提交的时候
 54 --但是SQL默认设置是每一语句运行完毕就提交事务
 55 
 56 
 57 --可重复读(repeatable read)
 58 --指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事务都不能在当前
 59 --事务完成之前修改由当前事务读取的数据
 60 --在这个隔离级别上,对事务中的每个语句所读取的全部数据都设置了共享锁,并且该共享锁
 61 --一直保持到事务完成为止。这样可以防止其他事务修改当前事务读取的任何行。其他事务
 62 --可以插入与当前事务所发出语句的搜索条件相匹配的新行。如果当前事务随后重试执行该
 63 --语句,他会检索新行,从而产生幻读
 64 --由于共享锁一直保持到事务结束,而不是每个语句结束时释放,所以并发性低于默认的
 65 --read committed隔离级别。此选项只在必要时使用
 66 
 67 
 68 --可序列化(serializable)
 69 --可序列化的要求:
 70 --语句不能读取已由其他事务修改但尚未提交的数据
 71 --任何其他事务都不能在当前事务完成之前修改由当前事务读取的数据
 72 --在当前事务完成之前,其他事务不能使用当前事务中任何语句读取的键值插入新行
 73 
 74 --SQL通过加范围锁的方式来实现可序列化。范围锁处于与事务中执行的每个语句的搜索
 75 --条件相匹配的键值范围之内。这样可以阻止其他事务更新或插入任何行,从而限定当前
 76 --事务所执行的任何语句。这意味着如果再次执行事务中的任何语句,则这些语句便会
 77 --读取同一组行。在事务完成之前将一直保持范围锁
 78 
 79 --这是限制最多的隔离级别,因为他锁定了键的整个范围,并在事务完成之前一直保持范围锁。
 80 --因为并发级别最低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有select
 81 --语句中的所有表上设置holdlock相同
 82 
 83 
 84 
 85 --SQLSERVER其实通过对共享锁申请和释放机制的不同处理,来实现不同事务隔离级别的
 86 
 87 --不同隔离级别对共享锁的不同处理方式
 88 --隔离级别            是否申请共享锁          何时释放              有无范围锁
 89 --未提交读                不申请                无                     无
 90 --已提交读                申请                  当前语句做完时         无
 91 --可重复读                申请                  事务提交时             无
 92 --可序列化                申请                  事务提交时             有
 93 
 94 --也就是说,事务隔离级别越高,共享锁被持有的时间越长。而可序列化还要申请粒度更高的
 95 --范围锁,并一直持有到事务结束。所以,如果阻塞发生在共享锁上面,可以通过降低事务
 96 --隔离级别得到缓解
 97 
 98 
 99 --需要说明的是,SQL在处理排他锁的时候,4个事务隔离级别都是一样的。都是在修改的时候申请
100 --直到事务提交的时候释放(而不是语句结束以后就立即释放)。如果阻塞是发生在排他锁上面,
101 --是不能通过降低事务隔离级别得到缓解的

 

posted @ 2013-07-27 16:18 桦仔 阅读(...) 评论(...)  编辑 收藏