我有一个Java应用程序正在数据库上执行多个并发CRUD操作。我正在添加对SQLServer的支持,但是在并发删除期间出现死锁问题。经过一些调查,看来问题可能是由于特定表上的锁升级所致。
为了解决此问题,我决定使用UPDLOCK提示使所有在该表上的读取都“为了更新”,以便避免死锁。但是,我仍然看到问题。我已在SQLServer中启用了跟踪,并在SQLServer日志中找到了以下死锁跟踪:
遇到死锁....打印死锁信息
等待图
节点数:1
密钥:5:72057594042384384(54048e7b3828)CleanCnt:3模式:X标志:0x0
资助清单1:
所有者:0x03D08C40模式:X Flg:0x0参考:0寿命:02000000 SPID:62 ECID:0 XactLockInfo:0x04834274
SPID:62 ECID:0语句类型:DELETE行号:1
输入Buf:语言事件:(@ P0 nvarchar(4000))从part_data中删除,其中part_id = @ P0
被要求:
ResType:LockOwner Stype:'OR'Xdes:0x04B511C8模式:U SPID:60 BatchID:0 ECID:0 TaskProxy:(0x058BE378)Value:0x3d08500 Cost:(0/1296)
节点数:2
密钥:5:72057594042384384(f903d6d6e0ac)CleanCnt:2模式:X标志:0x0
资助清单0:
所有者:0x03D088A0模式:X Flg:0x0参考:0寿命:02000000 SPID:60 ECID:0 XactLockInfo:0x04B511EC
SPID:60 ECID:0语句类型:DELETE行号:1
输入Buf:语言事件:(@ P0 nvarchar(4000))从part_data中删除,其中part_id = @ P0
被要求:
ResType:LockOwner Stype:'OR'Xdes:0x04834250模式:U SPID:62 BatchID:0 ECID:0 TaskProxy:(0x047BA378)Value:0x3d089e0 Cost:(0/4588)
受害者资源所有者:
ResType:LockOwner Stype:'OR'Xdes:0x04B511C8模式:U SPID:60 BatchID:0 ECID:0 TaskProxy:(0x058BE378)Value:0x3d08500 Cost:(0/1296)
SQLServer Profiler将其显示为两个拥有更新(U)锁并尝试升级为独占(X)锁的客户端。我阅读的SQLServer文档说,在给定的时间,只有一个客户端可以在表上具有(U)锁,所以我想知道为什么我看到跟踪中显示的情况。
在该跟踪中引用的数据库对象是外键上的索引。如果有解决此类问题的经验的人可以提供建议,那将是很大的帮助。
谢谢,
布拉德
编辑根据要求添加了死锁图xml:
<deadlock-list>
<deadlock victim="process989018">
<process-list>
<process id="process6aa7a8" taskpriority="0" logused="4844" waitresource="KEY: 5:72057594042384384 (5504bdfb7529)" waittime="9859" ownerId="613553" transactionname="implicit_transaction" lasttranstarted="2009-05-08T11:52:39.137" XDES="0x5fcbc30" lockMode="U" schedulerid="1" kpid="3516" status="suspended" spid="59" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2009-05-08T11:52:39.183" lastbatchcompleted="2009-05-08T11:52:39.183" clientapp="jTDS" hostname="LOIRE" hostpid="123" loginname="sa" isolationlevel="read committed (2)" xactid="613553" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="40" sqlhandle="0x0200000007c76c39efdd8317c6fa7b611b4fd958f05cfcf4">
delete from part_data where part_id = @P0 </frame>
</executionStack>
<inputbuf>(@P0 nvarchar(4000))delete from part_data where part_id = @P0</inputbuf>
</process>
<process id="process989018" taskpriority="0" logused="1528" waitresource="KEY: 5:72057594042384384 (5e0405cb0377)" waittime="1250" ownerId="613558" transactionname="implicit_transaction" lasttranstarted="2009-05-08T11:52:39.183" XDES="0x48318f0" lockMode="U" schedulerid="2" kpid="2692" status="suspended" spid="60" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2009-05-08T11:52:39.183" lastbatchcompleted="2009-05-08T11:52:39.183" clientapp="jTDS" hostname="LOIRE" hostpid="123" loginname="sa" isolationlevel="read committed (2)" xactid="613558" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="40" sqlhandle="0x0200000007c76c39efdd8317c6fa7b611b4fd958f05cfcf4">
delete from part_data where part_id = @P0 </frame>
</executionStack>
<inputbuf>(@P0 nvarchar(4000))delete from part_data where part_id = @P0</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594042384384" dbid="5" objectname="MESSAGESTOREDB61.dbo.part_data" indexname="idx_part_data_part_id" id="lock3cab740" mode="X" associatedObjectId="72057594042384384">
<owner-list>
<owner id="process6aa7a8" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process989018" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594042384384" dbid="5" objectname="MESSAGESTOREDB61.dbo.part_data" indexname="idx_part_data_part_id" id="lock3cad340" mode="X" associatedObjectId="72057594042384384">
<owner-list>
<owner id="process989018" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process6aa7a8" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
最佳答案
欢迎可怕。
我上次遇到这种情况是因为更新或删除找不到合适的索引来帮助它隔离所影响的行。由于使用非覆盖索引修改记录的位置,这导致了不稳定的锁定升级。
因此,如果可以隔离某些查询,请检查它们的sql,看看是否无法尝试提供一些覆盖索引。
覆盖索引是包括特定where子句中所有字段的索引。