Hibernate使用hibernate.jdbc.batch_versioned_data保存过时数据

环境

Hibernate 4.2

ojdbc6 – Oracle 11.2.0.3.0 JDBC 4.0

Oracle数据库11g

问题

我们遵循了许多建议来配置我们的Hibernate批处理方式如下:

100 true true true 

我们检查了日志,并且看到生成的SQL语句已经批处理。 但是,如果两个事务同时修改相同的版本化实体行,Hibernate将成功提交它们,导致最后提交的事务中的冲突更新丢失(非冲突数据保存在两个事务中,因此最后一个事务离开数据库处于不一致的状态)。

令人惊讶的是,关于这种行为的文档很少。 Hibernate官方文档说:

hibernate.jdbc.batch_versioned_data

如果JDBC驱动程序从executeBatch()返回正确的行计数,请将此属性设置为true。 打开此选项通常是安全的。 然后,Hibernate将使用批量DML来自动生成版本化数据。 默认为false。

通常安全 ? 在注意到整个版本控制被破坏之前,我们几乎将其发送到生产环境。

我们在五年前发布了一篇描述这种奇怪现象的博客 。 很明显,Hibernate很长一段时间没有做过任何事情。

Hibernate有这样的行为吗? 它从jdbc驱动程序获取更新行的计数未知的信息,为什么它不会抛出exception来指示它,而是留下版本检查已成功通过的印象?

oracle驱动程序应返回正确的行计数。 如果不是这样,我会感到惊讶。 您是否能够确认驱动程序的结果是否正确? 您可以打开Hibernate日志记录来检查这一点。

要检查的事情:

  1. 记录发送到数据库的实际SQL,并检查where子句中是否提到了version列。 不确定Hibernate日志记录是否通过批处理来记录SQL,您可能不得不采用不同的方式来记录SQL(例如,p6spy)

  2. 如果在并发更新期间正确返回行计数,则应用程序正常工作。 通过检查版本列的值是否已更新得到更正来确认。

更新根据以下链接,此问题已出现在Oracle驱动程序中,直到11g并在12c版本中修复

https://hibernate.atlassian.net/browse/HHH-3360

对于以前的Oracle版本,有一些应该有用的附加信息,即提供自定义解决方案。

其他资源: https : //hibernate.atlassian.net/browse/HHH-5070