使用 JDBC 处理可能出现的死锁的最佳方法

Best approach to handle a possible deadlock with JDBC

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

我学到了一些实现它的技巧 less 但并非永远不会,所以我担心正确处理这个问题。因此,假设我们正在通过 JDBC.

访问数据库

我没有在 documentation nor the official 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:

上找到了这个

Always be prepared to re-issue a transaction if it fails due to deadlock. Deadlocks are not dangerous. Just try again.

建议在应用程序代码中处理。

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

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

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

如果您允许用户 ad-hoc 对数据库进行写访问,那么您当然无法控制导致死锁的因素。但是我从来没有见过允许它的严肃系统。

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