SQL 更新导致死锁

标签 sql sql-server-2005 deadlock

我们最近将一些代码从 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)

这是跟踪中的死锁图:

Deadlock graph

我不明白运行完全相同的存储 proc 语句的 2 个人如何最终会在同一个语句上陷入死锁。第一个连接不应该锁定记录,迫使第二个连接等待它可用吗?对于造成这种僵局的原因,我还有什么可以调查的吗?可能是因为 OUTPUT 语句吗?

最佳答案

是的,有可能两个人执行相同的语句而不锁定第一次执行。我也生成了相同的场景。 SQL 脏读问题。
使用 提供了相同的解决方案ISOLATION LEVEL READ COMMITTED transactions .
它指定语句不能读取已被其他事务修改但未提交的数据。这可以防止脏读。当前事务中的各个语句之间的其他事务可以更改数据,从而导致不可重复读取或幻像数据。
有关详细信息,请参阅 Microsoft 知识库 [http://msdn.microsoft.com/en-us/library/ms173763.aspx]

摘要: - 只需将您的查询放在事务中 [prefer - ISOLATION LEVEL READ COMMITTED transactions]

关于SQL 更新导致死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10794717/

相关文章:

从主队列调用 dispatch_sync 时 iOS 死锁,执行的 block 保存到核心数据

mysql - 如何根据条件选择一个表中的所有记录,而第二个表中没有记录

sql - 查找 DISTINCT 缺失的 SQL 依赖项

java - 使用java swing更新sql上的数据

mysql - ActiveRecord3 死锁重试

c - 如果我在下面的代码片段中跳过 waiting[i] = false 会发生什么?

mysql - 合并单个表上多个 select 语句的结果

MySQL SELECT 仅不是空值

sql - 仅从日期时间获取日期时 - 哪个最好,为什么?

sql-server-2005 - SQL Server 2005 : what does the letter N for (. ..WHERE 名称如 N'F%')