【发布时间】:2015-05-26 13:30:25
【问题描述】:
我在更新时遇到了死锁。事务级别设置为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>
【问题讨论】:
-
你为什么在这里使用NOLOCK?事实上,你为什么要使用它?通常应避免使用表格提示,但您在此处的代码是导致死锁的秘诀。您明确地忽略了表上的任何锁,然后尝试更新该行。这意味着如果其他东西在该行上锁定了您正在尝试更新它。删除这些表提示,您的查询将自行修复。 blogs.msdn.com/b/davidlean/archive/2009/04/06/…
-
每个事务处理多行,对吧?这不应该为一行死锁(不过,您可能会遇到双重写入,这是一个错误)。
-
将
(NOLOCK)更改为(UPDLOCK, HOLDLOCK)并从 UPDATE 语句中删除 UPDLOCK。然后将块包装在显式事务中。 -
@SeanLange 感谢您的提示,我在选择语句中为 UPDLOCK 更改了 NOLOCK,它似乎有效。我的应用程序出现了很多死锁问题。 NOLOCK 和 UPDLOCK 帮助解决了这些问题。如果没有表提示,我几乎每次都在更新数据库上的相同记录时遇到死锁。在我的情况下,双重写入不会是一个错误。
-
@DanGuzman 该语句已在交易中。但是事务是从
TransactionScope中的 C# 代码设置的,并且我将事务级别设置为 Read Committed。
标签: sql-server tsql sql-update database-deadlocks