对于以下事务,我偶尔会在同一个订单同时调用此事务时收到Dead Lock错误。
BEGIN TRANSACTION
IF EXISTS (SELECT orderID FROM [Orders]WHERE orderID=@OrderId)
BEGIN
UPDATE [Orders] SET
[orderXml] =@orderXml
,[updatedDateTime] = @updatedDateTime
WHERE
[orderId] = @OrderId AND @updatedDateTime > updatedDateTime
END
if @@ROWCOUNT = 0
BEGIN
DELETE OrderLine
WHERE
orderID=@OrderId
END
COMMIT TRANSACTION
DeadLock Graph:
<resource-list>
<keylock hobtid="72057594039042048" dbid="13" objectname="OrderDB.dbo.Orders" indexname="PK_Order" id="lockac2e8d80" mode="U" associatedObjectId="72057594039042048">
<owner-list>
<owner id="process80736748" mode="U"/>
</owner-list>
<waiter-list>
<waiter id="process80739b88" mode="U" requestType="convert"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594039042048" dbid="13" objectname=" OrderDB.dbo.Orders" indexname="PK_Order" id="lockac2e8d80" mode="U" associatedObjectId="72057594039042048">
<owner-list>
<owner id="process80739b88" mode="S"/>
</owner-list>
<waiter-list>
<waiter id="process80736748" mode="X" requestType="convert"/>
</waiter-list>
</keylock>
</resource-list>
PK_Order是Orders Table的OrderId(varchar)列的主键。该表还在updatedDateTime(datetime2)列上有一个非聚集索引。
问题:当我在上面的更新语句中使用WITH(UPDLOCK)提示时,死锁似乎消失了。 是否建议使用UPDLOCK提示或我应该将事务隔离级别设置为Serializable。 也建议在上面的delete语句中使用UPDLOCK提示。
答案 0 :(得分:1)
这是一个典型的死锁案例。访问模式是read-then-write。两个trans都读,然后都写不出来。
你采取“写”锁(UPDLOCK
)的解决方案是好的。使用我认为最适合此类案例的UPDLOCK, ROWLOCK, HOLDLOCK
。
SERIALIZABLE
没有帮助,因为该模式仍然是read-then-write。
DELETE
不需要额外的锁定,因为该事务已获得对相关行的独占访问权。