【问题标题】:Deadlock between 2 transactions using ROWLOCK and UPDLOCK使用 ROWLOCK 和 UPDLOCK 的 2 个事务之间的死锁
【发布时间】:2013-12-02 13:49:37
【问题描述】:

我有一些使用 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

这发生在网络服务器上,因此有时同时有 2 个事务。这里的问题是,有时对 2 个非常不同的 id 的 2 个请求会陷入僵局。

起初没有提示,也没有设置事务隔离。我认为这是造成问题的页锁,所以我添加了 ROWLOCK 并 READ UNCOMMITED。然后我发现了一个关于在 SHARED 事务中进行更新的问题,所以我使用了 UPDLOCK。现在我的想法已经不多了。

大家是不是觉得很熟悉?

【问题讨论】:

  • 读取未提交,然后是行锁、上锁。真的吗?
  • AFAIK 隔离级别定义了事务的默认值,并且可以使用提示进行更改。那里有 40 个请求,其中未提交的读取是正确的级别。也就是说,我更习惯于 postgres,所有这些 SQLServer 锁和提示对我来说都非常神秘。
  • “像 40 个请求,其中未提交的读取是适当的级别” - 我唯一使用未提交的读取是报告绝对一致性不是最重要的查询。
  • 也许...我只是按照我们数据库管理员的指示进行操作。正如我所说,我试图了解这些事情是如何运作的。
  • 也许您的 DBAdmin 实际上并不知道他们在做什么?只是一个想法……它确实发生了……

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


【解决方案1】:

当涉及同一张表上的多个索引时,我曾见过这种类型的死锁。您应该捕获并研究死锁图。

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

dbcc traceon(1222,-1)

然后,启动 SQL Profiler 会话并在 Locks 下添加名为 Deadlock Graph 的事件。请务必选择此事件的所有列。我所看到的是一个循环区块链,其中一个事务将一个键锁定在非聚集索引中,然后尝试更新某些字段,这将需要更新聚集索引,但其他一些事务锁定了相同的聚集索引中的键,然后试图将键锁定在第一个事务持有的非聚集索引中。

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

【讨论】:

    猜你喜欢
    • 2021-04-23
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    相关资源
    最近更新 更多