使用 c (updlock) 更新时的 MSSQL 死锁

MSSQL Deadlock when update withc (updlock)

我在更新时遇到了死锁。事务级别设置为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>

您正在为每个事务处理多行,对吗?这不应该死锁一行

不过,您可能会得到双插入,这是一个错误。两个会话可能得出没有行的结论,然后都将插入。

有两种方法可以确保安全:

  1. 发出select WITH (ROWLOCK, UPDLOCK, HOLDLOCK)这是一个众所周知的锁提示序列。它需要一把锁来稳定您正在操作的数据。在这条语句有 运行 之后,您就拥有了自己的数据。然后您可以插入或更新。您也可以将所有三个语句合并为一个 MERGE 但您仍然需要锁提示。此外,您必须有某种全局顺序来发出写入。现在,无论您如何锁定,如果一个会话写入 A、B 而另一个会话按顺序写入 B、A,则始终会出现死锁。获得全局顺序的一种简单方法是在单个 [=11= 中发出所有写入] 陈述。查询处理器通常会选择一个执行顺序的计划。
  2. 使用 SERIALIZABLE 隔离并重试死锁。