为什么会出现死锁?

Grz*_*zes 6 sql deadlock transactions isolation-level sql-server-2008

我使用一个包含两个简单查询的小事务:select和update:

SELECT * FROM XYZ WHERE ABC = DEF
Run Code Online (Sandbox Code Playgroud)

UPDATE XYZ SET ABC = 123
WHERE ABC = DEF
Run Code Online (Sandbox Code Playgroud)

事务通常由两个线程启动,并且取决于隔离级别发生死锁(RepeatableRead,Serialization).两个事务都尝试读取和更新完全相同的行.我想知道为什么会这样.导致死锁的查询顺序是什么?我已经读过一些关于锁(共享,独占)以及每个隔离级别锁定的持续时间,但我仍然不完全理解......

我甚至准备了一个总是导致死锁的简单测试.我查看了SSMS和SQL Server Profiler中的测试结果.我开始第一次查询,然后立即开始第二次.

第一个查询:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT ...
WAITFOR DELAY '00:00:04'
UPDATE ...
COMMIT
Run Code Online (Sandbox Code Playgroud)

第二个查询:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT ...
UPDATE ...
COMMIT
Run Code Online (Sandbox Code Playgroud)

现在我无法向您显示详细的日志,但它看起来不那么像这样(我很可能错过了Lock:死锁等等):

(1) SQL:BatchStarting: First query
(2) SQL:BatchStarting: Second query
(3) Lock:timeout for second query
(4) Lock:timeout for first query
(5) Deadlock graph
Run Code Online (Sandbox Code Playgroud)

如果我理解了锁,在(1)第一个查询采用共享锁(执行SELECT),然后进入休眠状态并保持共享锁直到事务结束.在(2)中,第二个查询也采用共享锁(SELECT),但在同一行上存在共享锁时不能采用独占锁(UPDATE),这会导致Lock:timeout.但我无法解释为什么发生第二次查询的超时.可能我不太了解整个过程.任何人都能给出一个很好的解释吗?

我没有注意到使用ReadCommitted的死锁,但我担心它们可能会发生.你推荐什么解决方案?

Dav*_*vid 5

当两个或多个任务通过锁定其他任务试图锁定的资源的每个任务永久阻塞时,就会发生死锁

http://msdn.microsoft.com/en-us/library/ms177433.aspx