3

我们最近将一些代码从 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 语句吗?

4

1 回答 1

1

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

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

于 2012-05-29T07:51:44.370 回答