Hi all,
I’m moving a SpringBoot Application (2.6.4) based on hibernate 5.6.4 from Java 11 to Java17.
I have an issue with at least Azul Jvm.
We are using optimist locking with @version
All my updates are now failing with an OptimisticLock exception.
Our entities are like this:
public class MyEntity {
@CreatedDate
private ZonedDateTime createdAt;
@Version
private ZonedDateTime updatedAt;
When we do this sequence (without any concurrency on a DB):
MyEntity aChild = new MyEntity(251L, "uid", "a node", 2, 251L);
entityManager.persist(aChild);
entityManager.flush();
aChild.setLevel(3);
entityManager.flush();
The last line throws an OptimisticLock exception.
After investigation, it’s due to the usage of nanoseconds in the Java code that is not supported in H2 nor Postgres (our 2 DBs for tests and run).
They only support Timestemp with 6 digits (by default for H2, could be 9, but only 6 digits for postgresql).
- H2: “If fractional seconds precision is specified it should be from 0 to 9, 6 is default.”
Data Types - Postgresql:
time,timestamp, andintervalaccept an optional precision valuepwhich specifies the number of fractional digits retained in the seconds field. By default, there is no explicit bound on precision. The allowed range ofpis from 0 to 6.
PostgreSQL: Documentation: 14: 8.5. Date/Time Types
The previous sequence runs in our previous JVM produces this sql exchange:
[ main] org.hibernate.SQL : insert into myTable (created_at, updated_at, level, name, parent_id, res grp, sort_number, uid, dtype, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, 'Node', ?)
[ main] o.h.t.d.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [2020-09-09T10:15:20+02:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [2] as [TIMESTAMP] - [2022-03-08T10:29:00.108198+01:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [3] as [INTEGER] - [2]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [a node]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [5] as [BIGINT] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [6] as [BOOLEAN] - [false]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [7] as [VARCHAR] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [8] as [BIGINT] - [251]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [9] as [VARCHAR] - [uid]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [10] as [BIGINT] - [251]
[ main] org.hibernate.SQL : update myTable set created_at=?, updated_at=?, level=?, name=?, parent_id=?, res=?, grp=?, sort_number=? where id=? and updated_at=?
[ main] o.h.t.d.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [2020-09-09T10:15:20+02:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [2] as [TIMESTAMP] - [2022-03-08T10:29:00.155311+01:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [3] as [INTEGER] - [3]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [a node]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [5] as [BIGINT] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [6] as [BOOLEAN] - [false]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [7] as [VARCHAR] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [8] as [BIGINT] - [251]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [9] as [BIGINT] - [251]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [10] as [TIMESTAMP] - [2022-03-08T10:29:00.108198+01:00[Europe/Zurich]]
In this case everything is ok.
A request on the table return this:
select updated_at from myTable;
UPDATED_AT
2022-03-08 10:29:00.108198
Please note that we have 6 digits: 10:29:00.108198
After the upgrade to Java 17:
[ main] org.hibernate.SQL : insert into myTable (created_at, updated_at, level, name, parent_id, res, grp, sort_number, uid, dtype, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, 'Node', ?)
[ main] o.h.t.d.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [2020-09-09T10:15:20+02:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [2] as [TIMESTAMP] - [2022-03-08T08:54:09.379015900+01:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [3] as [INTEGER] - [2]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [a node]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [5] as [BIGINT] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [6] as [BOOLEAN] - [false]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [7] as [VARCHAR] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [8] as [BIGINT] - [251]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [9] as [VARCHAR] - [uid]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [10] as [BIGINT] - [251]
[ main] org.hibernate.SQL : update myTable set created_at=?, updated_at=?, level=?, name=?, parent_id=?, res=?, grp=?, sort_number=? where id=? and updated_at=?
[ main] o.h.t.d.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [2020-09-09T10:15:20+02:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [2] as [TIMESTAMP] - [2022-03-08T08:54:09.539991700+01:00[Europe/Zurich]]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [3] as [INTEGER] - [3]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [a node]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [5] as [BIGINT] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [6] as [BOOLEAN] - [false]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [7] as [VARCHAR] - [null]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [8] as [BIGINT] - [251]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [9] as [BIGINT] - [251]
[ main] o.h.t.d.sql.BasicBinder : binding parameter [10] as [TIMESTAMP] - [2022-03-08T08:54:09.379015900+01:00[Europe/Zurich]]
[ main] o.h.e.j.b.i.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
[ main] o.h.e.j.b.i.BatchingBatch : HHH000315: Exception executing batch [org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: update myTable set created_at=?, updated_at=?, level=?, name=?, parent_id=?, res=?, grp=?, sort_number=? where id=? and updated_at=?], SQL: update myTable set created_at=?, updated_at=?, level=?, name=?, parent_id=?, res=?, grp=?, sort_number=? where id=? and updated_at=?
The difference is the usage of nanos in the parameter value: :54:09.539991700
The second request fails (the update) because the where clause is:
updated_at = 2022-03-08T08:54:09.379015900 but the value in the DB has been truncated:
select updated_at from myTable;
UPDATED_AT
2022-03-08 09:29:00.108198
The where clause doesn’t match the raw and fail with the OptimisticLock exception.
Does exist a parameter to fix this behaviour ?
I don’t find anything in hibernate nor jdk.
Thanks for you help,
Philippe