更新withc(updlock)时MSSQL死锁

时间:2015-05-26 13:30:26

标签: sql-server tsql sql-update database-deadlocks

我在更新时遇到了僵局。事务级别设置为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 个答案:

答案 0 :(得分:1)

您正在为每个交易处理多个行,对吗?这不应该是一行的死锁

但是,您可能会获得双重插入,这是一个错误。两个会话可能会得出结论,没有行,然后两个都会插入。

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

  1. 发出select WITH (ROWLOCK, UPDLOCK, HOLDLOCK),这是一个众所周知的锁定提示序列。它需要一个锁定来稳定您正在操作的数据。运行此语句后,您可以获得自己的数据。然后,您可以插入或更新。您还可以将所有三个语句折叠为一个MERGE,但仍需要锁定提示。此外,您必须具有某种发出写入的全局顺序。现在,无论你如何锁定,如果一个会话按顺序写入A,B和其他写入顺序B,A总是会出现死锁。获得全局顺序的一种简单方法是在单个{{1}中发出所有写入声明。查询处理器通常会选择一个强制执行订单的计划。
  2. 使用MERGE隔离并重试死锁。