【问题标题】:Best approach to handle a possible deadlock with JDBC使用 JDBC 处理可能的死锁的最佳方法
【发布时间】:2019-09-25 04:20:17
【问题描述】:

所以,我最近发现了deadlocks 的存在。尽管我从未有过,但我知道这可能是测试环境之外的问题,因为有很多用户同时访问。

我学到了一些技巧来实现它更少,但不是永远不会,所以我担心正确处理这个问题。所以,假设我们通过 JDBC 访问数据库。

我在documentationofficial examples 中都没有找到对死锁处理的任何引用,因为它们只是回滚(或者如果不可能,则打印和异常):

} catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
        if (con != null) {
            try {
                System.err.print("Transaction is being rolled back");
                con.rollback();
            } catch(SQLException excep) {
                JDBCTutorialUtilities.printSQLException(excep);
            }
        }
    }

据我了解阅读文档,如果 executeUpdate() 方法发现死锁,它不会以任何方式重试。

搜索不同的解决方案我找到了this approach,它将整个事情包装成一个循环,每次尝试之间都有一个计数器和一个睡眠

所以,我的问题是:

  1. 除了抛出异常之外,JDBC 是否以任何方式处理死锁?任何语言的任何库都会(至少可选地)重试查询?
  2. 在使用 JDBC 实现的死块敏感场景中,您将如何处理此问题?
  3. 您是否在自定义数据库访问方法中防止这种情况发生?另外,您是否拥有它们,或者您每次访问数据库时只使用默认行?
  4. 当需要的行被解锁时,为什么数据库引擎不重新启动受害者查询?

编辑:我在 MySQL documentation 上找到了这个:

如果由于死锁而失败,请随时准备重新发出事务。死锁并不危险。请再试一次。

这建议在应用程序代码上处理它。

有什么想法吗?提前谢谢你。

【问题讨论】:

  • 1.不,它不会,因为它不能。死锁是需要在业务逻辑中处理的错误。 2. 没有专门针对 JDBC 的解决方案。为什么?因为处理死锁取决于您的业务逻辑,所以没有一种万能的方法来处理死锁。

标签: java mysql sql jdbc database-deadlocks


【解决方案1】:

虽然缓解死锁可能有一定的价值,但在精心设计的系统中,死锁应该非常少见。你提到学习一些如何避免它们的技巧,但这是我自己的清单:

  • 在许多系统中,您总是先锁定顶级对象/实体,然后再更新它们的子表。例如,订单处理系统可能有许多不同的表来保存数据,但您总是会首先尝试锁定顶级订单实体。
  • 更一般地说,如果所有访问数据库的代码始终以相同的顺序锁定实体,则不会发生死锁。 (例如,如果一个连接按顺序锁定表 A 和 C 中的行,而另一个连接按顺序锁定 A、B 和 C,则无论这些锁定的时间如何,都不会发生死锁。)
  • 系统还可以设计为消除大多数锁定。例如,如果数据 被追加而不是编辑,则不需要锁定。
  • 在 NoSQL 数据库中,所有相关数据通常保存在单个对象中。不需要锁定,甚至数据库可能不支持。

如果您允许用户对数据库进行临时写入访问,那么您当然无法控制导致死锁的因素。但我从未见过允许它的严肃系统。

因此,与其担心应对死锁,不如将所有精力都花在完全避免它们上。当您看到死锁时,您会发现系统中的错误导致它发生。

【讨论】:

  • 在同一个表中是否会发生死锁,同时运行大量大规模行更新?或者锁定工作总是在同一个方向上,防止这种情况发生在一个唯一的表中?
  • 连接 1 锁定行 A 然后 B,连接 2 锁定行 B 然后 A。但在实际业务场景中几乎总是可以避免,因为更新不是随机的 - 行在商业意义上是相关的,这通常意味着可以先锁定更高级别的对象。如果没有,您仍然可以通过始终锁定排序键顺序来避免它(假设您有所有需要预先锁定的键。)
  • 重新阅读您的评论,我错过了您所说的大规模行更新,可能是单语句更新。这是个好问题!我猜想一些或大多数数据库在执行多行更新时使用一致的顺序,以避免死锁。或者他们可能会锁定整个页面或表本身。我不确定——它还没有出现。要么我先锁定一个父对象,要么它是一次性迁移/转换方案。
  • @Bampfer 您忘记了您的死锁预防列表:一次只允许一个用户更新数据库..;)
  • 有趣的方法,MB。为什么要锁定单个行、页或表?只需锁定整个数据库! :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
  • 2011-12-14
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
相关资源
最近更新 更多