<deadlock-list>
<deadlock victim="process17392264e8">
<process-list>
<process id="process17392264e8" taskpriority="5" logused="0" waitresource="OBJECT: 7:2018106230:0 " waittime="4449" ownerId="394509589" transactionname="user_transaction" lasttranstarted="2019-06-05T12:06:41.320" XDES="0x18ed9516f0" lockMode="IX" schedulerid="4" kpid="8348" status="suspended" spid="143" sbid="0" ecid="0" priority="-5" trancount="2" lastbatchstarted="2019-06-05T12:06:41.310" lastbatchcompleted="2019-06-05T12:06:41.310" lastattention="1900-01-01T00:00:00.310" clientapp="Helios Orange" hostname="???" hostpid="508" loginname="???" isolationlevel="read committed (2)" xactid="394509589" currentdb="7" currentdbname="XXXXXX" lockTimeout="4294967295" clientoption1="673384544" clientoption2="128568">
<executionStack>
<frame procname="XXXXXX.dbo.hp_ZdvojeniKonstrukceATech" line="73" stmtstart="6876" stmtend="7250" sqlhandle="0x03000700efbf9d27f8924d01e9a8000001000000000000000000000000000000000000000000000000000000">
UPDATE CZ SET IntPermanentniZmena=0
FROM TabDavka D
INNER JOIN TabCZmeny CZ ON (CZ.ID=D.ZmenaOd AND CZ.IntPermanentniZmena=1)
WHERE D.IDDilce=@IDKusovni </frame>
<frame procname="adhoc" line="2" stmtstart="44" stmtend="152" sqlhandle="0x010007000f5ba906f09b4b6f0700000000000000000000000000000000000000000000000000000000000000">
EXEC @ret=hp_ZdvojeniKonstrukceATech 120234, 39008, 1 </frame>
</executionStack>
<inputbuf>
DECLARE @ret integer
EXEC @ret=hp_ZdvojeniKonstrukceATech 120234, 39008, 1
SELECT @ret </inputbuf>
</process>
<process id="process15bf6ce8c8" taskpriority="5" logused="0" waitresource="OBJECT: 7:2018106230:0 " waittime="6020" ownerId="394493191" transactionname="user_transaction" lasttranstarted="2019-06-05T12:06:39.750" XDES="0x16fb190ea0" lockMode="IX" schedulerid="1" kpid="3940" status="suspended" spid="83" sbid="0" ecid="0" priority="-5" trancount="2" lastbatchstarted="2019-06-05T12:06:39.750" lastbatchcompleted="2019-06-05T12:06:39.750" lastattention="1900-01-01T00:00:00.750" clientapp="Helios Orange" hostname="???" hostpid="14924" loginname="???" isolationlevel="read committed (2)" xactid="394493191" currentdb="7" currentdbname="XXXXXX" lockTimeout="4294967295" clientoption1="673384544" clientoption2="128568">
<executionStack>
<frame procname="XXXXXX.dbo.hp_ZdvojeniKonstrukceATech" line="73" stmtstart="6876" stmtend="7250" sqlhandle="0x03000700efbf9d27f8924d01e9a8000001000000000000000000000000000000000000000000000000000000">
UPDATE CZ SET IntPermanentniZmena=0
FROM TabDavka D
INNER JOIN TabCZmeny CZ ON (CZ.ID=D.ZmenaOd AND CZ.IntPermanentniZmena=1)
WHERE D.IDDilce=@IDKusovni </frame>
<frame procname="adhoc" line="2" stmtstart="44" stmtend="152" sqlhandle="0x0100070009fde604c031f1451a00000000000000000000000000000000000000000000000000000000000000">
EXEC @ret=hp_ZdvojeniKonstrukceATech 120073, 39047, 1 </frame>
</executionStack>
<inputbuf>
DECLARE @ret integer
EXEC @ret=hp_ZdvojeniKonstrukceATech 120073, 39047, 1
SELECT @ret </inputbuf>
</process>
</process-list>
<resource-list>
<objectlock lockPartition="0" objid="2018106230" subresource="FULL" dbid="7" objectname="XXXXXX.dbo.TabCzmeny" id="lock134d414780" mode="S" associatedObjectId="2018106230">
<owner-list>
<owner id="process15bf6ce8c8" mode="S"/>
<owner id="process15bf6ce8c8" mode="IX" requestType="convert"/>
</owner-list>
<waiter-list>
<waiter id="process17392264e8" mode="IX" requestType="convert"/>
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="2018106230" subresource="FULL" dbid="7" objectname="XXXXXX.dbo.TabCzmeny" id="lock134d414780" mode="S" associatedObjectId="2018106230">
<owner-list>
<owner id="process17392264e8" mode="S"/>
<owner id="process17392264e8" mode="IX" requestType="convert"/>
</owner-list>
<waiter-list>
<waiter id="process15bf6ce8c8" mode="IX" requestType="convert"/>
</waiter-list>
</objectlock>
</resource-list>
</deadlock>
</deadlock-list>
它位于同一资源(表)上,并且是由从两个会话调用的同一过程引起的。
程序的简化流程是这样的:
SELECT @Variable = Column FROM Table WITH (HOLDLOCK)
…
UPDATE Table SET...
我将不胜感激任何建议如何防止这种死锁情况?
问题是在事务期间在该资源上
HOLDLOCK
创建“共享”锁(锁)。Mode: S
这不会阻止其他进程(例如在另一个会话中执行的同一进程)将自己的“共享”锁放在同一资源上。但是随后两个会话都到达了UPDATE
试图将其锁转换(即升级)为“Intent eXclusive”(Mode: IX
锁)的语句,由于另一个会话仍持有其“共享”锁,因此无法完成。如果 的目的
HOLDLOCK
是为该会话保留行(以便其他人无法修改它),那么您需要防止其他会话能够在同一资源上放置自己的“共享”锁(同时,当然)。一种方法是更改
HOLDLOCK
toUPDLOCK
(即“更新”锁)。这允许其他事务对同一资源(如HOLDLOCK
)采取相同的锁定,但其中一个事务可以转换/升级为XLOCK
然后将强制所有其他事务(仍然具有它们的UPDLOCK
)等待直到事务结束(不像HOLDLOCK
) . 此外,虽然锁仍然是“更新”锁(即在转换为“排他”锁之前),但其他事务/会话可以读取该资源(也像HOLDLOCK
)。如果至少有一行要更新并且锁转换为“排他”锁,并且您有其他进程需要访问此表而无需等待所有这些更新完成,那么您有几个选择:
WITH (NOLOCK)
提示(读取已修改但尚未提交,因此可能会回滚行)WITH (READPAST)
提示(完全跳过行,就好像它不存在一样)SNAPSHOT ISOLATION
(读取当前/未修改的行)以下测试应说明所有这些:
查询选项卡 A
将以下内容粘贴到 SSMS(即会话)中的一个查询选项卡中,并仅执行块引用中的语句(现在;即
USE
,CREATE TABLE
和INSERT
)查询选项卡 B
将以下内容粘贴到 SSMS 中的另一个查询选项卡(即另一个会话),但不要执行它(还)。
查询选项卡 C
将以下内容粘贴到 SSMS 中的另一个查询选项卡(即另一个会话),但不要执行它(还)。
主要测试
sys.dm_tran_locks
),您应该会看到 6 行左右。如果您在系统中有一堆东西,请取消注释该WHERE
子句并用“查询选项卡 A”和“查询选项卡 B”的会话 ID(即 SPID)替换x
和。y
SELECT ... FROM dbo.test ...
查询中的每一个返回 3 行。到目前为止,只使用了“更新”锁。UPDATE
语句,几秒钟:SELECT ... FROM dbo.test ...
查询中返回 2 行(即READPAST
)NOLOCK
)中获取所有 3 行,但第 3 行将显示未提交的值。GO
存在,就在这个查询之前,以便其他人可以在这个查询时返回他们的结果集被封锁)