java.time types not usable for optimistic locking due to precision truncation

Description

It was reported (Java 17 @version and nanoseconds truncation ) that java.time types use nanosecond precision when generating version values. When the database only supports e.g. microseconds, OptimisticLockException can occur due to the truncation in SQL. Ideally, we would now pass in the requested precision information into the org.hibernate.type.descriptor.java.VersionJavaType methods to solve this, though that would be a breaking change between 6.0.0.CR and Final.

Activity

Show:

Christian Beikov September 29, 2023 at 10:25 AM

Yeah, that looks like a good workaround for ORM 5.

Stefan Fußenegger September 22, 2023 at 3:51 PM

for anyone stuck with an earlier version I believe using a custom type extending InstantType is the best workaround:

import java.time.Instant; import java.time.temporal.ChronoUnit; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.type.InstantType; /** * workaround for <a href="https://hibernate.atlassian.net/browse/HHH-15135">HHH-15135 java.time types not usable for * optimistic locking due to precision truncation</a> */ public abstract class InstantPrecisionType extends InstantType { private final ChronoUnit _unit; private InstantPrecisionType(final ChronoUnit unit) { _unit = unit; } @Override public Instant seed(final SharedSessionContractImplementor session) { return truncated(super.seed(session)); } @Override public Instant next(final Instant current, final SharedSessionContractImplementor session) { return truncated(super.next(current, session)); } private Instant truncated(final Instant instant) { return instant == null ? null : instant.truncatedTo(_unit); } public class Millis extends InstantPrecisionType { public Millis() { super(ChronoUnit.MILLIS); } } public class Micros extends InstantPrecisionType { public Micros() { super(ChronoUnit.MICROS); } } public class Nanos extends InstantPrecisionType { public Nanos() { super(ChronoUnit.NANOS); } } }

Usage with @Type (and optionally @TypeDef):

@Data @Entity @TypeDef(typeClass = InstantMillisType.class, name = "millis") public class Foo { @Version @Type(type = "millis") private Instant updated; }

Maybe someone would like to confirm that this is a viable workaround? (Note @Convert won’t work as it’s not suitable for @Version properties)

Fixed

Assignee

Christian Beikov

Reporter

Components

Fix versions

Priority

Created March 21, 2022 at 5:19 PM
Updated September 29, 2023 at 10:25 AM
Resolved April 5, 2022 at 6:29 AM