SQL 更新导致死锁
Posted
技术标签:
【中文标题】SQL 更新导致死锁【英文标题】:SQL Update causing deadlock 【发布时间】:2012-05-29 07:21:10 【问题描述】:我们最近将一些代码从 C# 移至 SQL (SQL Server 2005) 以尝试防止并发问题。然而,在 SQL 中,我们现在遇到了死锁。我无法重新创建导致死锁的步骤,但是我能够在 SQL 跟踪中捕获它。
表上没有触发器,但有几个索引支持搜索。
根据跟踪,死锁是由两个人在同一条记录上运行相同的更新语句引起的:
UPDATE myTable
SET
col2 = @var2 + col2
,col3 = CASE WHEN (@Var2 <= 0 OR @Var2 + Col2 <= 0)
THEN Col3
ELSE
CONVERT
(
dbo.MoneyInfo,
@var3 + ':' + @Var4 + ':' + @Var5
)
END
OUTPUT INSERTED.Col0,
Inserted.Col2,
Inserted.Col3
WHERE Col0 = @Var1
dbo.MoneyInfo
是自定义 CLR 类型。该表看起来像:
create table myTable
(
col0 int,
col1 int,
col2 decimal(18,2),
col3 dbo.MoneyInfo
)
col0 为非聚集主键(PK_Stock),col1 为聚集索引(IX_Item)
这是跟踪中的死锁图:
我不明白运行完全相同的存储 proc 语句的 2 个人怎么会在同一个语句上陷入死锁。第一个连接不应该锁定记录,迫使第二个连接等待它可用吗?对于造成这种僵局的原因,我还有什么可以调查的吗?会不会是 OUTPUT 语句的原因?
【问题讨论】:
这是否在一个事务中,该事务中是否还有其他语句? 它在一个事务中。不过,此表上没有其他查询。 这个问题是否通过更改隔离级别得到解决?我遇到了类似的死锁场景。 它为我们解决了问题 【参考方案1】:是的,有可能两个人执行相同的语句而不锁定第一次执行。我也生成了相同的场景。 SQL 脏读问题。 使用ISOLATION LEVEL READ COMMITTED 事务 提供了相同的解决方案。 它指定语句不能读取已被其他事务修改但未提交的数据。这可以防止脏读。当前事务中的各个语句之间的其他事务可以更改数据,从而导致不可重复读取或幻像数据。 有关详细信息,请参阅 Microsoft 知识库 [http://msdn.microsoft.com/en-us/library/ms173763.aspx]
总结:- 只需将您的查询放入 Transaction [prefer - ISOLATION LEVEL READ COMMITTED transactions]
【讨论】:
肯定有 2 个人在运行它,我有跟踪文件显示。我将尝试将此事务的隔离级别设置为 READ COMMITTED 并查看它是否有所作为。以上是关于SQL 更新导致死锁的主要内容,如果未能解决你的问题,请参考以下文章
在 Firebird 脚本中创建表会导致“元数据更新失败”并出现死锁
NSFetchedResultsController 在同一持久存储的后台更新时提供表视图导致死锁