一尘不染

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

hibernate

环境

hibernate4.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>

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

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

hibernate.jdbc.batch_versioned_data

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

通常安全 吗?在通知整个版本已损坏之前,我们几乎将其发送到了生产环境。

我们搜寻了五年前发布的博客,描述了这种怪异。显然,Hibernate很长时间没有对此做任何事情。

Hibernate为何如此表现?它从jdbc驱动程序获得信息,即更新的行数未知,为什么它不抛出异常来指示它,却给人留下版本检查已成功通过的印象?


阅读 909

收藏
2020-06-20

共1个答案

一尘不染

oracle驱动程序应返回正确的行数。如果不是这种情况,我会感到惊讶。您能够确认驱动程序的结果正确吗?您可以打开Hibernate日志记录进行检查。

需要检查的几件事:

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

  2. 如果在并发更新期间正确返回了行计数,则该应用程序运行正常。通过检查版本列的值是否已更新来更正此内容。

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

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

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

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

2020-06-20