使用 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,它 将整个事情包装成一个带有计数器的循环,并在每次尝试之间休眠 。
所以,我的问题是:
- JDBC 除了抛出异常之外,是否以任何方式处理死锁?任何语言的任何库都会(至少可选地)重试查询?
- 在使用 JDBC 实现的死块敏感场景中,您将如何处理这个问题?
- 您是否在自定义数据库访问方法中阻止了这一点?另外,您有它们还是每次访问数据库时都使用默认行?
- 当需要的行解锁时,为什么数据库引擎不重新启动受害者查询?
编辑:我在 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 对数据库进行写访问,那么您当然无法控制导致死锁的因素。但是我从来没有见过允许它的严肃系统。
因此,与其担心响应死锁,不如将所有精力花在完全避免死锁上。当您看到死锁时,您会在系统中找到导致死锁发生的错误。
所以,我最近发现了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,它 将整个事情包装成一个带有计数器的循环,并在每次尝试之间休眠 。
所以,我的问题是:
- JDBC 除了抛出异常之外,是否以任何方式处理死锁?任何语言的任何库都会(至少可选地)重试查询?
- 在使用 JDBC 实现的死块敏感场景中,您将如何处理这个问题?
- 您是否在自定义数据库访问方法中阻止了这一点?另外,您有它们还是每次访问数据库时都使用默认行?
- 当需要的行解锁时,为什么数据库引擎不重新启动受害者查询?
编辑:我在 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 对数据库进行写访问,那么您当然无法控制导致死锁的因素。但是我从来没有见过允许它的严肃系统。
因此,与其担心响应死锁,不如将所有精力花在完全避免死锁上。当您看到死锁时,您会在系统中找到导致死锁发生的错误。