sql server语言 - 使用c (updlock)更新MSSQL时死锁



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

每个事务处理多行,对吗?这应该不会为一行出现死锁

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

有两种方法可以使其安全:

  1. 发出select WITH (ROWLOCK, UPDLOCK, HOLDLOCK),这是一个众所周知的锁提示序列。它需要一个锁来稳定您正在操作的数据。运行完这条语句后,您就拥有了自己的数据。然后可以插入或更新。您也可以将这三个语句合并到一个MERGE中,但是仍然需要锁提示。此外,您还必须有某种全球性的秩序来发布写操作。现在不管你怎么锁,如果一个会话写a, B,而另一个会话按顺序B, a写,总是会出现死锁。获得全局顺序的一个简单方法是在单个MERGE语句中发出所有写操作。查询处理器通常选择一个强制顺序的计划。
  2. 使用SERIALIZABLE隔离并在死锁时重试。

最新更新