1.假设有一个事务A
1
2
3
4
5
6
|
-----事务A------- begin tran
update [TestDB].[dbo].tb_score set score=score+1 where id=3
waitfor delay '00:00:10' --延迟10秒读取
SELECT * FROM [TestDB].[dbo].tb_score
commit TRANSACTION
|
它会运行10s左右,主要是更新表tb_score。在这10s期间,有语句对该表做查询。
1
|
SELECT * FROM [TestDB].[dbo].tb_score
|
该语句会被阻塞,因为update会默认加上共享锁,直到10s后,事务A提交后才能查出结果。
以上语句就等介于下面的语句,因为事务隔离级别READ COMMITTED是SQLServer的默认设置。
1
2
3
4
5
|
SET TRANSACTION ISOLATION LEVEL READ committed begin tran
SELECT * FROM [TestDB].[dbo].tb_score
commit TRANSACTION
|
此处,值得注意的事情是,在事务A中当update语句更新的时候,如果要更新的目标值=现在的值,比如,在id=3的记录,score已经等于100了的情况下,语句如果是update [TestDB].[dbo].tb_score set score=100 where id=3。那么执行SELECT *  FROM [TestDB].[dbo].tb_score将不被阻塞。原因猜测是sql不对这种实际不做更改的Update语句加锁
2.还是以上事务A
把查询语句改为如下
语句B:
1
2
3
4
5
|
SET TRANSACTION ISOLATION LEVEL READ uncommitted begin tran
SELECT * FROM [TestDB].[dbo].tb_score
commit TRANSACTION
|
此时
SELECT *  FROM [TestDB].[dbo].tb_score语句被允许“脏读”
该查询未等事务A提交,就已经读出,并且读书的值为A以修改但未提交的值。
例如id=3的score=100,运行A事务的时候,score=101了,此时运行语句B,则立刻返回出id=3的score=101,而不管A是否真的已经提交或者rollback。
还有一点要注意,当你设置了READ uncommitted,那么接下来的sql语句都会是 READ uncommitted。msdn上:一次只能设置一个隔离级别选项,而且设置的选项将一直对那个连接始终有效,直到显式更改该选项为止。事务中执行的所有读取操作都会在指定的隔离级别的规则下运行,除非语句的 FROM 子句中的表提示为表指定了其他锁定行为或版本控制行为。所以在查询分析器中做实验的时候,要注意,一旦设置了READ uncommitted,接下来在当前窗口中的语句都是如此。
3
1
2
3
4
5
|
-----事务A------- begin tran
select * from [TestDB].[dbo].tb_score with (tablockx) where id=3
waitfor delay '00:00:10' --延迟10秒读取
commit TRANSACTION
|
此事务对表加了表级别的排它锁。因此在此期间,
1
2
3
4
5
|
SET TRANSACTION ISOLATION LEVEL READ uncommitted begin tran
SELECT * FROM [TestDB].[dbo].tb_score where id=1
commit TRANSACTION
|
更多内容,可以看
http://msdn.microsoft.com/zh-cn/library/ms187373.aspx
http://msdn.microsoft.com/zh-cn/library/ms173763.aspx
4
此处有些疑问:
两个事务
1
2
3
4
5
6
7
8
9
10
11
|
-----事务A------- begin tran
select * from [TestDB].[dbo].tb_score with (updlock,rowlock) where id=3 waitfor delay '00:00:10' --延迟10秒读取
update [TestDB].[dbo].tb_score set score=score+1 where id=3 commit TRANSACTION
-----事务B------ SET TRANSACTION ISOLATION LEVEL READ committed begin tran
select * from [TestDB].[dbo].tb_score with (updlock,rowlock) where
id=3 commit TRANSACTION
|
我的理解是,事务A运行的时候,对id=3的加了行锁,还有更新锁,更新锁的话一定要等到事务运行完才能再被获取。
因此事务A运行的时候,事务B也马上运行,但是事务B也要对改行获取更新锁,因此被阻塞在此,所以最后运行的结果是A运行完了B在运行。以上一切正常
但是把事务B改成
-----事务B-------
1
2
3
4
|
SET TRANSACTION ISOLATION LEVEL READ committed begin tran
select * from [TestDB].[dbo].tb_score with (updlock,rowlock) where id=1
commit TRANSACTION
|
事务B对id=1的行加锁。
那么我的理解是,既然事务A加锁的对象是id=3的行,那么和事务B根本不会有什么冲突。但是事实上,运行事务A后马上运行B,发现事务B也会被阻塞。并且事务A还会发出异常错误:说是检测到死锁。
Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
本人愚钝,百思不解,求专家指教。
本文转自cnn23711151CTO博客,原文链接:http://blog.51cto.com/cnn237111/638055 ,如需转载请自行联系原作者