使用ROWLOCK和UPDLOCK的2个事务之间的死锁

时间:2013-12-02 13:49:37

标签: ruby-on-rails sql-server sql-server-2008 transactions deadlock

我使用SQLServer 2008rc2有一些Ruby on Rails代码,我遇到了死锁问题。 从SQL的角度来看,这就是我的代码的样子:

begin transaction
  SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
  select * from table1 with (rowlock, updlock) where id = 1234 -- fetch the object with a lock
  -- do several queries, all with nolock or no hint
  -- this can take a few seconds
  update table1 with(rowlock) set x = 'y' where id = 1234
end

这发生在Web服务器上,因此有时同时有2个事务。这里的问题是,有时2个非常不同的ID的请求会被锁定。

首先,提示不存在,并且未设置事务隔离。我认为这是一个创建问题的分页锁,所以我添加了ROWLOCK和READ UNCOMMITED。然后我发现了在SHARED事务中进行更新的问题,因此我使用了UPDLOCK。现在我的想法已经不多了。

听起来对任何人来说都很熟悉吗?

1 个答案:

答案 0 :(得分:0)

在涉及同一个表上的多个索引之前,我已经看到过这种类型的死锁。您应该捕获并研究死锁图。

为此,请在SSMS中设置跟踪标志1222:

dbcc traceon(1222,-1)

然后,启动SQL事件探查器会话并在“锁定”下添加名为“死锁图”的事件。请务必选择此活动的所有列。我看到的是一个循环块链,其中一个事务锁定非聚集索引中的一个键,然后尝试更新某个字段,这需要更新聚簇索引,但其他一些事务锁定了密钥索引中的密钥,然后尝试将密钥锁定在第一个事务所持有的非聚集索引中。

请记住,行锁提示实际上更像是一个建议,如果它认为锁定开销太高,数据库引擎可能不会尊重它,它可能只是升级到锁定整个索引/表,视情况而定是