针对并发事务出现的数据不一致性,提出了4个级别的解决方法:
隔离级别 | 第一类丢失更新 | 脏读 | 不可重复读 | 第二类丢失更新 | 虚读 | 未提交读 | 未发生 | 发生 | 发生 | 发生 | 发生 | 提交读 | 未发生 | 未发生 | 发生 | 发生 | 发生 | 可重复读 | 未发生 | 未发生 | 未发生 | 未发生 | 发生 | 串行化 | 未发生 | 未发生 | 未发生 | 未发生 | 未发生 |
1.未提交读 采用排它锁(update, insert, delete),解决了丢失更新问题,但是脏读仍然会出现。 例1: begin tran update t1 set t1.name = 'yyy' waitfor delay '00:00:10' --等待10秒 rollback tran 例2: set transaction isolation level read uncommitted begin tran select * from t1 commit tran 结果:例2返回更新后的值(yyy),尽管最后更新回滚了。
2.提交读 采用共享锁(select)+排它锁(update, insert, delete),解决了丢失更新问题,也解决了脏读问题。SQL Server默认属于这个隔离级别。
3.可重复读 采用修改锁(update)+排它锁(insert, delete)+共享锁(select),解决了丢失更新问题,脏读问题,但是会出现幻像读。 例3: set transaction isolation level repeatable read begin tran select * from t1 waitfor delay '00:00:10' select * from t1 commit tran 例4: set transaction isolation level repeatable read begin tran delete from t1 where t1.id = 8 commit tran 结果:例3,2次返回的结果集都一样,都含有t1.id=8的行。
4.可串行读 采用一个事务执行完后,才能执行第2个事务(被阻塞)的串行方式,解决了以上所有的问题。 例5: set transaction isolation level serializable begin tran select * from t1 waitfor delay '00:00:10' commit tran 例6: set transaction isolation level serializable begin tran delete from t1 where t1.id = 9 commit tran 结果:例5,2次都返回一样的结果,是删除前的。只能说明实现了可重复读级别的事务。 例7: set transaction isolation level serializable begin tran select * from t1 waitfor delay '00:00:10' select * from t1 commit tran 例8: set transaction isolation level serializable begin tran insert into t1(name) values('zhang') commit tran 结果:例7,2次都返回一样的结果,都是添加前的结果集。结合前面的例子说明是串行级别。
|