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
, andinterval
accept an optional precision valuep
which specifies the number of fractional digits retained in the seconds field. By default, there is no explicit bound on precision. The allowed range ofp
is 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