Hibernate 使用 hibernate.jdbc.batch_versioned_data 保存陈旧数据

Hibernate saves stale data with hibernate.jdbc.batch_versioned_data

环境

休眠 4.2

ojdbc6 - Oracle 11.2.0.3.0 JDBC 4.0

甲骨文数据库 11g

问题

我们按照许多建议按照以下方式配置 Hibernate 批处理:

<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property>

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

令人惊讶的是,关于此行为的文档非常少。 Hibernate 官方 documentation 说:

hibernate.jdbc.batch_versioned_data

Set this property to true if your JDBC driver returns correct row counts from executeBatch(). It is usually safe to turn this option on. Hibernate will then use batched DML for automatically versioned data. Defaults to false.

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

我们用谷歌搜索了一篇 blog 五年前描述这种怪事的帖子;很明显 Hibernate 已经很久没有做这方面的任何事情了。

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

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

要检查的几件事:

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

  2. 如果行计数在并发更新期间被正确 returned,则应用程序运行良好。通过检查版本列的值是否已更正来确认这一点。

更新 根据以下link,此问题在 11g 之前的 Oracle 驱动程序中一直存在,并在版本 12c

中得到修复

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

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

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