四、隔离级别与锁
数据库是利用锁和隔离级别来共同处理数据库的并发的。DB2数据库用来尝试实施并发性的方法之一是通过使用隔离级别,它决定在第一个事务访问数据时,如何对其他事务锁定或隔离该事务所使用的数据。DB2隔离级别分为如下四种:
a、可重复读(Repeatable Read,RR)
b、读稳定性(Read Stability,RS)
c、游标稳定性(Cursor Stability,CS)
d、未提交读(Uncommitted Read,UR)
DB2默认的隔离级别为:游标稳定性(CS)
1、可重复读(RR -- Repeatable Read)
a、可重复读隔离级别是最严格的隔离级别。在使用它时,一个事务的影响完全与其他并发事务隔离:脏读、不可重复读、幻像读都不会发生。当使用可重复读隔离级别时,在事务执行期间共享(S)锁定该事务以任何方式引用的所有行。因此,如果在同一个事务中发出同一个SELECT语句两次或更多次,那么产生的结果数据集总是相同的。因此,使用可重复读隔离级别的事务可以多次检索同一行集,并可以对它们执行任意操作,直到由提交或回滚操作终止事务。但是,在事务存在期间,不允许其他事务执行会影响该事务正在访问的任何行的插入、更新或删除操作。为了确保这种行为,锁定该事务所引用的每一行 -- 而不是仅锁定被实际检索或修改的那些行。因此,如果一个表中有1000行,但只检索两行,则整个表(1000行,而不仅是被检索的两行)都会被锁定。
b、如果使用可重复读隔离级别,不管从表中读多少数据,整个表上都加S锁,直到该事务被提交或回滚,表上的锁才会被释放。这样可以保证在一个事务中即使多次读取同一行,得到的值也不会改变。另外,在同一个事务中如果以同样的搜索标准重新打开已被处理过的游标,那么得到的结果集不会改变。可重复读相对于读稳定性而言,加锁的范围更大。对于读稳定性,应用程序只对符合要求的所有行加锁,而对于可重复读,应用程序将对整个表都加S锁。
c、可重复读(RR),不可能出现丢失更新、脏读和幻像读的情况;
2、读稳定性(RS -- Read Stability)
a、读稳定性隔离级别没有可重复读隔离级别那么严格。读稳定性(RS)可以防止脏读和不可重复读,但可能出现幻像读。在使用这个隔离级别时,只锁定事务实际检索和修改的行。因此,如果一个表有1000行,但只检索两行(通过索引扫描),则只有被检索的两行(而不是所扫描的1000行)被锁定。因此,如果在同一个事务中发出同一个select语句多次,那么每次产生的结果集可能不同。
b、与可重复读隔离级别一样,在读稳定性隔离级别下运行的事务可以检索一个行集,并可以对它们执行任意操作,直到事务终止。在这个事务存在期间,其他事务不能执行那些会影响这个事务检索到的行集的更新或删除操作(其他事务可以更新或删除 不影响该事务检索到的行集的数据);但是其他事务可以执行插入操作。如果插入的行与第一个事务的查询的选择条件匹配,那么这些行可能作为幻像出现在后续产生的结果数据集中。其他事务对其他行所作的更改,在提交之前是不可见的。
c、如果使用读稳定性(RS)这种隔离,在一个事务中将有N+1个锁,其中N是所有被读取(通过索引扫描)过的行的数目,这些行上都会被加上NS锁,在表上加1个IS锁。这些锁直到事务被提交或回滚,才会被释放。这样可以保证在一个事务中即使多次读取同一行,得到的值不不会改变。但是,使用读稳定性,在一个事务中,如果使用同样的搜索标准重新打开已被处理过的游标,那么结果集可能改变(可能会增加某些行,这些行被称为幻影行-Phantom)。这是因为RS不能阻止通过插入或更新操作在结果集中加入新行。
d、读稳定性(RS),只锁定应用程序在工作单元中检索的那些行。它确保在某个工作单元完成之前,在该工作单元运行期间的任何限定行读取不被其他应用程序进程更改,且确保不会读取由另一个应用程序所更改的任何行,直到该进程提交了这些更改。读稳定性,不可能出现“不可重复读”情形。
e、“读稳定性”,其中一个目标是提供较高的并行性程度以及数据的稳定视图。为了有助于达到此目的,优化器确保在发生锁定升级前不获取表级锁定。
f、“读稳定性”隔离级别最适用于包括下列所有特征的应用程序:
在并发环境下运行;
需要限定某些行在工作单元运行期间保持稳定;
在工作单元中不会多次发出相同的查询,或者在同一个工作单元中发出多次查询时,并不要求该查询获得相同的回答。
3、游标稳定性(CS -- Cursor Stability)
a、游标稳定性隔离级别,可以防止脏读,但有可能出现不可重复读和幻像读。游标稳定性只锁定事务声明并打开游标当前引用的行。
b、当使用游标稳定性隔离级别时,事务通过游标从表中检索行时,其他事务不能更新或删除游标所引用的行。但是,如果被锁定的行本身不是用索引访问的,那么其他事务可以将新的行添加到表中,以及对被游标锁定行前后的行进行更新和删除操作。所获取的锁一直有效,直到游标重定位或事务终止为止(如果游标重定位,原来行上的锁就被释放,并获得游标现在引用的行上的锁)。此外,如果事务修改了它检索到的任何行,那么在事务终止之前,其他事务不能更新或删除改行,即使游标不再位于被修改的行。例如:一个表中有1000行数据,我们只检索其中的两行数据,那么对于可重复读(RR)隔离级别会锁住整个表;读稳定性(RS)会对读到的数据(两行)加锁;游标稳定性(CS)隔离级别只对游标当前所在的那一行加锁,游标所在行的前一行和下一行都不加锁。
c、结果集中只有正在被读取的那一行(游标指向的行)将被加上NS锁,在表上加IS锁。其他未被处理的行上不被加锁。CS只能保证正在被处理的行的值不会被其他并发的程序所改变。
d、当在行上定位游标时,游标稳定性CS会锁定任何由应用程序的事务所访问的行。此锁定在读取下一行或终止事务之前有效。但是,如果更改了某一行上的任何数据,那么在对数据库提交更改之前必须挂起该锁定。
e、对于具有“游标稳定性”的应用程序已检索的行,当该行上有任何可更新的游标时,任何其他应用程序都不能更新或删除该行。“游标稳定性”应用程序不能查看其他应用程序的未提交更改。
f、与可重复读(RR)和读稳定性(RS)隔离级别一样,其他事务在其他行上进行的更改,在这些更改提交之前对使用游标稳定性(CS)隔离级别的事务(这时默认的隔离级别)来说是不可见的。
g、游标稳定性,可能会出现不可重复读和幻像读现象。
4、未提交读(UR - Uncommitted Read)
a、未提交读隔离级别是最不严格的隔离级别。实际上,在使用这个隔离级别时,仅当另一个事务试图删除或更改被检索的行所在表时,才会锁定这个事务检索的行。因为在使用这种隔离级别时,行通常保持未锁定状态,使用脏读、不可重复读和幻像读都可能会发生。因此,未提交读通常用于访问只读表和视图的事务,以及某些执行select语句的事务。
b、未提交读UR,运行应用程序读取其他事务未落实的更改。但是对于只读和可更新两种不同的游标类型而言,UR的工作方式有所不同。对于可更新的游标,当它使用隔离级别UR运行程序时,应用程序会自动使用隔离级别CS。
c、使用UR,对于只读操作,不加行锁。典型的只读操作包括:SELECT语句的结果集只读(比如语句中包括ORDER BY子句);定义游标时指明FOR FETCH ONLY或FOR READ ONLY。
d、UR,最大程度上允许并发;若需读取未提交的数据,该隔离级别是唯一选择。
e、只读游标可访问大多数其他事务的未提交的更改。但是,当该事务正在处理时,不能使用正由其他事务创建或删除的表、视图和索引。其他事务的任何其他更改在提交或回滚前都可被读取。
5、隔离级别的读取总结
脏读
不可重复 读幻像读
可重复读(RR) 否
否
否
读稳定性(RS) 否
否 是
游标稳定性(CS) 否
是 是
未提交读(UR) 是
是
是
6、名词解释:
a、脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
b、幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读。
c、不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。