Environment
Hibernate 4.2
ojdbc6 - Oracle 11.2.0.3.0 JDBC 4.0
Oracle Database 11g
The issue
We followed many recommendations to configure our Hibernate batching the following way:
<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>
We checked our logs, and we saw that generated SQL statements are batched. However, if two transactions modify the same versioned entity rows concurrently, Hibernate will successfully commit both of them, resulting in loosing conflicting updates in the transaction that committed last (non-conflicting data are saved in both transactions, thus the last transaction leaves the database in an inconsistent state).
Surprisingly, there is very little documentation on this behavior. Hibernate official documentation says:
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.
Usually safe? We almost sent this to production before noticing that the entire versioning is broken.
We googled out a blog posted five years ago that describes this weirdness; apparently Hibernate has not done anything regarding this for a long time.
Is there any reason why Hibernate behaves like this? It gets the information from the jdbc driver that the count of updated rows is unknown, why does it not throw an exception to indicate it, but rather leaves the impression that version check has passed successfully?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…