SQL Server事务的隔离级别
########## 数据库中数据的一致性 ##########
针对并发事务出现的数据不一致性,提出了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次都返回一样的结果,都是添加前的结果集。结合前面的例子说明是串行级别。