SQL Update导致死锁

时间:2012-05-29 07:21:10

标签: 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

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

1 个答案:

答案 0 :(得分:1)

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

摘要: - 只需将您的查询放入交易[prefer - ISOLATION LEVEL READ COMMITTED transactions]