ANSI SQL-92的non-Repeatable read和phantom row两种isolation level的差别

  • Post author:
  • Post category:其他


我可以通过set transaction isolation level来控制数据库的事务完整性,对事务完整性的破坏有三种情况

dirty read > non repeatable read > phantom row。dirty read谁都容易理解,书上写的也是很明白的,就是事务1可以读取到事务2还没有提交的被修改的数据。

主要就是后两个non repeatable read 和phantom row,以前看了书也没搞明白是怎么回事,今天又看了看书,并做了下实验总算弄明白了,以前书上讲的是没错,但是感觉没有把话说透了。

non repeatable read是这样的情况:

begin tran t2

select * from t where id = 1

这时候不进行commit tran,假如得到的结果是

id   name

1    hello

这时在另外的查询窗口里再开始一个事务

begin tran t1

update t set name = ‘hahaha’ where id = 1

commit tran

这时候,我们再回到事务t2的窗口,再执行 select * from t where id = 1,我们将能看到name变成了hahaha

这种情况在sqlserver的默认的read committed isolation level下是允许的。

而phantom row 的情况是:

begin tran t1

select * from t where name like ‘ha%’

假如返回的结果是

id     name

2       ha1

3       ha2

这时候在另一个查询窗口中开始另一个事务

begin tran t1

update t set name = ‘hahaha’ where id = 1

commit tran

然后再回到事务t1的窗口,还执行select * from t where name like ‘ha%’,这时候就会多查出id=1的那行。

猛一看non repeatable read 和phantom row好像没有太大差别,都是能在事务2中看到事务1已经提交的结果。关键是phantom row的情况下是不允许non repeatable read的情况出现。具体的来说,在只允许phantom row的情况下,对应sqlserver的set transaction isolation repeatable read,先开始一个查询的事务t1 它查询出了id 为1,2,3的三行,这时候t1没有提交,另外开始一个更新事务t2对id为2的行进行更新,这时候更新将无法进行,因为这种行为就属于non repeatable read的行为,但是如果对id为1,2,3之外的行进行更新,就不会有问题,如果对其他的行的更新后,使其他行的条件也符合事务t1中的刚才进行的查询的条件,则在事务T1没有被提交前再进行刚才的查询被修改后的行也会出现在查询结果中,这就出现了phantom row。

其实可以这样来理解,non repeatable read就是当一个事务在进行查询的时候,它不会对它查询到的行加锁,所以其他的事务可以来对其进行修改,但是在只允许phantom row的情况下,则是当一个事务在查询的时候,会对它查询到的行加锁,以防止其他的事务进行修改,但是不会对没有查询到的行进行加锁,其他的事务仍然可以对那些没被查到的行进行修改,当修改被提交之后,某些行符合了查询事务的查询的条件,则那些被修改的行也会被查询事务查询到,并被加上锁以防止被其他事务修改。如果是最严格的事务完整性的话,如果查询事务在更新事务之前开始,则更新事务所做的一切提交的修改都不应该被查询事务查询到,虽然我没做试验,但我估计当连PHANTOM ROW都不允许的情况下(这我只是估计而已,实际未必会是这样,没做实际验证,懒得做了),在sqlsever里恐怕当开始了查询事务之后,再开始的更新事务将根本无法运行下去,只能一直等到查询事务提交之后才能继续执行。



版权声明:本文为wpc820411原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。