我在更新时遇到了僵局。事务级别设置为Read Committed
。在这种情况下如何避免死锁?
在其他情况下,WITH (NOLOCK)
和WITH (UPDLOCK)
有所帮助
我收到了以下T-SQL
查询:
IF EXISTS (SELECT 1 FROM DEBTORS_CUSTOMERS WITH (NOLOCK) WHERE DebtorId = @DebtorId AND ClientFCCustomerNumber = @CustomerNumber)
UPDATE DEBTORS_CUSTOMERS WITH (UPDLOCK) SET StatusId = @StatusId WHERE DebtorId = @DebtorId AND ClientFCCustomerNumber = @CustomerNumber
ELSE
INSERT INTO DEBTORS_CUSTOMERS (DebtorId, ClientFCCustomerNumber, StatusId, DocId) SELECT @DebtorId, @CustomerNumber, @StatusId, @DocId
这是我得到的僵局:
<resource-list>
<keylock hobtid="72057594105692160" dbid="63" objectname="EOTestDataGenerator.dbo.DEBTORS_CUSTOMERS" indexname="PK_DEBTORS_CUSTOMERS" id="lockdf8abb00" mode="X" associatedObjectId="72057594105692160">
<owner-list>
<owner id="process3f59048" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="processbdbfa088" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594105692160" dbid="63" objectname="EOTestDataGenerator.dbo.DEBTORS_CUSTOMERS" indexname="PK_DEBTORS_CUSTOMERS" id="lockdf5ab200" mode="X" associatedObjectId="72057594105692160">
<owner-list>
<owner id="processbdbfa088" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process3f59048" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
答案 0 :(得分:1)
您正在为每个交易处理多个行,对吗?这不应该是一行的死锁
但是,您可能会获得双重插入,这是一个错误。两个会话可能会得出结论,没有行,然后两个都会插入。
有两种方法可以确保安全:
WITH (ROWLOCK, UPDLOCK, HOLDLOCK)
,这是一个众所周知的锁定提示序列。它需要一个锁定来稳定您正在操作的数据。运行此语句后,您可以获得自己的数据。然后,您可以插入或更新。您还可以将所有三个语句折叠为一个MERGE
,但仍需要锁定提示。此外,您必须具有某种发出写入的全局顺序。现在,无论你如何锁定,如果一个会话按顺序写入A,B和其他写入顺序B,A总是会出现死锁。获得全局顺序的一种简单方法是在单个{{1}中发出所有写入声明。查询处理器通常会选择一个强制执行订单的计划。MERGE
隔离并重试死锁。