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

Dra*_*vic 6 java oracle hibernate ojdbc

环境

休眠4.2

ojdbc6 - Oracle 11.2.0.3.0 JDBC 4.0

Oracle 数据库 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>
Run Code Online (Sandbox Code Playgroud)

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

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

hibernate.jdbc.batch_versioned_data

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

平时安全吗?我们几乎将其投入生产,然后才注意到整个版本控制已被破坏。

我们在谷歌上搜索了五年前发布的一篇博客,描述了这种奇怪的现象;显然 Hibernate 已经很长时间没有在这方面做任何事情了。

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

cod*_*ler 7

oracle 驱动程序应返回正确的行计数。如果情况并非如此,我会感到惊讶。您能确认司机的结果是正确的吗?您可以打开 Hibernate 日志记录来检查这一点。

有几件事需要检查:

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

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

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

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

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

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