我们最近将一些代码从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)
这是跟踪的死锁图:
我不明白运行完全相同的存储过程语句的2个人如何在同一个语句中陷入死锁。第一个连接不应该锁定记录,迫使第二个连接等待它变为可用吗?还有什么我可以查看造成这种僵局的原因吗?可能是因为OUTPUT声明?
答案 0 :(得分:1)
是的,2个人有可能执行相同的语句而不会锁定第一次执行。我也生成了相同的场景。一个SQL脏读问题。 通过使用 ISOLATION LEVEL READ COMMITTED事务提供了相同的解决方案。 它指定语句无法读取已修改但未由其他事务提交的数据。这可以防止脏读。数据可以由当前事务中的各个语句之间的其他事务更改,从而导致不可重复的读取或幻像数据。 有关更多信息,请参阅Microsoft知识库[http://msdn.microsoft.com/en-us/library/ms173763.aspx]
摘要: - 只需将您的查询放入交易[prefer - ISOLATION LEVEL READ COMMITTED transactions]