HHH-15774 @CurrentTimestamp takes over from @Source

... and make value generation work better with version properties.
This commit is contained in:
Gavin 2022-11-28 13:24:59 +01:00 committed by Gavin King
parent a9ac98b364
commit 993aae6095
22 changed files with 223 additions and 119 deletions

View File

@ -112,12 +112,7 @@ include::{sourcedir}/OptimisticLockingTest.java[tags=locking-optimistic-version-
----
====
Hibernate can retrieve the timestamp value from the database or the JVM, by reading the value you specify for the `@org.hibernate.annotations.Source` annotation.
The value can be either `org.hibernate.annotations.SourceType.DB` or `org.hibernate.annotations.SourceType.VM`.
The default behavior is to use the database, and database is also used if you don't specify the annotation at all.
The timestamp can also be generated by the database instead of Hibernate
if you use the `@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)` or the `@Source` annotation.
The timestamp can also be generated by the database, instead of by the VM, using the `@CurrentTimestamp` annotation, or even `@Generated(value = ALWAYS, sql = "current_timestamp")`.
[[locking-optimistic-version-timestamp-source-mapping-example]]
.Database-generated version timestamp mapping

View File

@ -6,17 +6,15 @@
*/
package org.hibernate.userguide.locking;
import java.util.Date;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Version;
import org.hibernate.annotations.Source;
import org.hibernate.annotations.SourceType;
import org.hibernate.annotations.CurrentTimestamp;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import java.time.LocalDateTime;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@ -47,6 +45,24 @@ public class VersionSourceTest extends BaseEntityManagerFunctionalTestCase {
assertNotNull(person.getVersion());
//end::locking-optimistic-version-timestamp-source-persist-example[]
});
sleep();
doInJPA(this::entityManagerFactory, entityManager -> {
Person person = entityManager.find(Person.class, 1L);
person.setFirstName("Jane");
});
sleep();
doInJPA(this::entityManagerFactory, entityManager -> {
Person person = entityManager.find(Person.class, 1L);
person.setFirstName("John");
});
}
private static void sleep() {
try {
Thread.sleep(300);
}
catch (InterruptedException ignored) {
}
}
//tag::locking-optimistic-version-timestamp-source-mapping-example[]
@ -60,9 +76,8 @@ public class VersionSourceTest extends BaseEntityManagerFunctionalTestCase {
private String lastName;
@Version
@Source(value = SourceType.DB)
private Date version;
@Version @CurrentTimestamp
private LocalDateTime version;
//end::locking-optimistic-version-timestamp-source-mapping-example[]
public Long getId() {
@ -89,11 +104,8 @@ public class VersionSourceTest extends BaseEntityManagerFunctionalTestCase {
this.lastName = lastName;
}
public Date getVersion() {
public LocalDateTime getVersion() {
return version;
}
//tag::locking-optimistic-version-timestamp-source-mapping-example[]
}
//end::locking-optimistic-version-timestamp-source-mapping-example[]
}

View File

@ -127,10 +127,14 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
final Object instance = getInstance();
persister.processInsertGeneratedProperties( getId(), instance, getState(), getSession() );
if ( persister.isVersionPropertyGenerated() ) {
version = Versioning.getVersion( getState(), persister);
version = Versioning.getVersion( getState(), persister );
}
entry.postUpdate( instance, getState(), version );
}
else if ( persister.isVersionPropertyGenerated() ) {
version = Versioning.getVersion( getState(), persister );
entry.postInsert( version );
}
}
private void putCacheIfNecessary() {

View File

@ -234,12 +234,12 @@ public class EntityUpdateAction extends EntityAction {
// this entity defines property generation, so process those generated
// values...
persister.processUpdateGeneratedProperties( id, instance, state, session );
if ( persister.isVersionPropertyGenerated() ) {
nextVersion = Versioning.getVersion( state, persister);
}
}
// have the entity entry doAfterTransactionCompletion post-update processing, passing it the
// update state and the new version (if one).
if ( persister.isVersionPropertyGenerated() ) {
nextVersion = Versioning.getVersion( state, persister );
}
entry.postUpdate( instance, state, nextVersion );
}

View File

@ -16,33 +16,25 @@ import java.lang.annotation.Target;
import org.hibernate.tuple.CreationTimestampGeneration;
/**
* Marks a property as the creation timestamp of the containing entity.
* The property value is set to the current VM datetime when the owning
* entity is made persistent for the first time.
* Specifies that the annotated field of property is a generated <em>creation timestamp</em>.
* The timestamp is generated just once, when an entity instance is inserted in the database.
* <p>
* The annotated field or property must be of one of the following types:
* <ul>
* <li>{@link java.util.Date}</li>
* <li>{@link java.util.Calendar}</li>
* <li>{@link java.sql.Date}</li>
* <li>{@link java.sql.Time}</li>
* <li>{@link java.sql.Timestamp}</li>
* <li>{@link java.time.Instant}</li>
* <li>{@link java.time.LocalDate}</li>
* <li>{@link java.time.LocalDateTime}</li>
* <li>{@link java.time.LocalTime}</li>
* <li>{@link java.time.MonthDay}</li>
* <li>{@link java.time.OffsetDateTime}</li>
* <li>{@link java.time.OffsetTime}</li>
* <li>{@link java.time.Year}</li>
* <li>{@link java.time.YearMonth}</li>
* <li>{@link java.time.ZonedDateTime}</li>
* </ul>
* By default, the timestamp is generated by {@linkplain java.time.Clock#instant() in memory},
* but this may be changed by explicitly specifying the {@link #source}.
* Otherwise, this annotation is a synonym for
* {@link CurrentTimestamp @CurrentTimestamp(timing=INSERT,source=VM)}.
*
* @author Gunnar Morling
*
* @see CurrentTimestamp
*/
@ValueGenerationType(generatedBy = CreationTimestampGeneration.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, METHOD })
public @interface CreationTimestamp {
/**
* Specifies how the timestamp is generated. By default, it is generated
* in memory, which saves a round trip to the database.
*/
SourceType source() default SourceType.VM;
}

View File

@ -15,17 +15,62 @@ import java.lang.annotation.Target;
import org.hibernate.tuple.GenerationTiming;
/**
* Specifies that the database {@code current_timestamp} function is used to
* generate values of the annotated attribute, based on {@link #timing()}.
* Specifies that the annotated field of property is a generated timestamp,
* and also specifies the {@linkplain #timing() timing} of the timestamp
* generation, and whether it is generated in Java or by the database:
* <ul>
* <li>{@link SourceType#VM source = VM} indicates that the virtual machine
* {@linkplain java.time.Clock#instant() current instant}
* is used, and
* <li>{@link SourceType#DB source = DB} indicates that the database
* {@code current_timestamp} function should be used.
* </ul>
* By default, the timestamp is generated by the database, which requires
* an extra round trip to the database to fetch the generated value.
* <p>
* This annotation may be used in combination with the JPA-defined
* {@link jakarta.persistence.Version} annotation.
* <p>
* The annotated property may be of any one of the following types:
* {@link java.util.Date},
* {@link java.util.Calendar},
* {@link java.sql.Date},
* {@link java.sql.Time},
* {@link java.sql.Timestamp},
* {@link java.time.Instant},
* {@link java.time.LocalDate},
* {@link java.time.LocalDateTime},
* {@link java.time.LocalTime},
* {@link java.time.MonthDay},
* {@link java.time.OffsetDateTime},
* {@link java.time.OffsetTime},
* {@link java.time.Year},
* {@link java.time.YearMonth}, or
* {@link java.time.ZonedDateTime}.
*
* @see CurrentTimestampGeneration
*
* @author Steve Ebersole
*
* @see UpdateTimestamp
* @see CreationTimestamp
*/
@ValueGenerationType(generatedBy = CurrentTimestampGeneration.class)
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE } )
@Inherited
public @interface CurrentTimestamp {
GenerationTiming timing();
/**
* Determines when the timestamp is generated. But default, it is updated
* when any SQL {@code insert} or {@code update} statement is executed.
* If it should be generated just once, on the initial SQL {@code insert},
* explicitly specify {@link GenerationTiming#INSERT timing = INSERT}.
*/
GenerationTiming timing() default GenerationTiming.ALWAYS;
/**
* Specifies how the timestamp is generated. By default, it is generated
* by the database, and fetched using a subsequent {@code select} statement.
*/
SourceType source() default SourceType.DB;
}

View File

@ -6,13 +6,15 @@
*/
package org.hibernate.annotations;
import org.hibernate.dialect.Dialect;
import org.hibernate.tuple.AnnotationValueGeneration;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.TimestampGenerators;
import org.hibernate.tuple.ValueGenerator;
/**
* Value generation strategy for using the database `current_timestamp` function to generate
* the values
* Value generation strategy using the database {@code current_timestamp}
* function or the JVM current instant.
*
* @see CurrentTimestamp
*
@ -20,10 +22,15 @@ import org.hibernate.tuple.ValueGenerator;
*/
public class CurrentTimestampGeneration implements AnnotationValueGeneration<CurrentTimestamp> {
private GenerationTiming timing;
private ValueGenerator<?> generator;
@Override
public void initialize(CurrentTimestamp annotation, Class<?> propertyType) {
this.timing = annotation.timing();
if ( annotation.source() == SourceType.VM ) {
// ValueGenerator is only used for in-VM generation
generator = TimestampGenerators.get( propertyType );
}
timing = annotation.timing();
}
@Override
@ -33,8 +40,7 @@ public class CurrentTimestampGeneration implements AnnotationValueGeneration<Cur
@Override
public ValueGenerator<?> getValueGenerator() {
// ValueGenerator is only used for in-VM generations
return null;
return generator;
}
@Override
@ -46,4 +52,9 @@ public class CurrentTimestampGeneration implements AnnotationValueGeneration<Cur
public String getDatabaseGeneratedReferencedColumnValue() {
return "current_timestamp";
}
@Override
public String getDatabaseGeneratedReferencedColumnValue(Dialect dialect) {
return dialect.currentTimestamp();
}
}

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.annotations;
import org.hibernate.Remove;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@ -24,9 +26,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* <li>{@link SourceType#DB} indicates that the database
* {@code current_timestamp} function should be used.
* </ul>
* For example, the following timestamp is generated by the
* database:
* <pre>
* {@code
* @Version @Source(DB)
* private LocalDateTime version;
* }
* </pre>
* This annotation is always used in conjunction with the JPA
* {@link jakarta.persistence.Version @Version} annotation.
*
* @author Hardy Ferentschik
*
* @see jakarta.persistence.Version
*
* @deprecated use {@link CurrentTimestamp} instead
*/
@Deprecated(since = "6.2") @Remove
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface Source {

View File

@ -7,34 +7,30 @@
package org.hibernate.annotations;
/**
* Specifies the source of a generated {@link java.sql.Timestamp}.
* <p>
* Timestamps are generated by calling methods of
* {@link org.hibernate.type.descriptor.java.VersionJavaType}.
* Specifies the source of a generated value, either the virtual machine,
* or the database.
*
* @see CurrentTimestamp#source()
* @see UpdateTimestamp#source()
* @see CreationTimestamp#source()
* @see Source
*
* @author Hardy Ferentschik
*/
public enum SourceType {
/**
* The virtual machine {@linkplain java.time.Clock#instant()
* current instance} is the source of the generated timestamp.
* Indicates that values are generated in the Java virtual machine.
* <p>
* For a generated timestamp, {@link java.time.Clock#instant()} might
* be the source.
*/
VM,
/**
* The database {@code current_timestamp} function (or equivalent)
* is the source of the generated timestamp.
* Indicates that values are generated by the database.
* <p>
* For a generated timestamp, the {@code current_timestamp} function
* might be the source.
*/
DB;
/**
* The corresponding {@link org.hibernate.type.BasicType} name.
*
* @return The corresponding type name.
*/
public String typeName() {
return this == SourceType.DB ? "dbtimestamp" : "timestamp";
}
}

View File

@ -16,28 +16,15 @@ import java.lang.annotation.Target;
import org.hibernate.tuple.UpdateTimestampGeneration;
/**
* Marks a property as the update timestamp of the containing entity.
* The property value will be set to the current VM datetime whenever
* the owning entity is updated.
* Specifies that the annotated field of property is a generated <em>update timestamp.</em>
* The timestamp is regenerated every time an entity instance is updated in the database.
* <p>
* The annotated field or property must be of one of the following types:
* <ul>
* <li>{@link java.util.Date}</li>
* <li>{@link java.util.Calendar}</li>
* <li>{@link java.sql.Date}</li>
* <li>{@link java.sql.Time}</li>
* <li>{@link java.sql.Timestamp}</li>
* <li>{@link java.time.Instant}</li>
* <li>{@link java.time.LocalDate}</li>
* <li>{@link java.time.LocalDateTime}</li>
* <li>{@link java.time.LocalTime}</li>
* <li>{@link java.time.MonthDay}</li>
* <li>{@link java.time.OffsetDateTime}</li>
* <li>{@link java.time.OffsetTime}</li>
* <li>{@link java.time.Year}</li>
* <li>{@link java.time.YearMonth}</li>
* <li>{@link java.time.ZonedDateTime}</li>
* </ul>
* By default, the timestamp is generated {@linkplain java.time.Clock#instant() in memory},
* but this may be changed by explicitly specifying the {@link #source}.
* Otherwise, this annotation is a synonym for
* {@link CurrentTimestamp @CurrentTimestamp(source=VM)}.
*
* @see CurrentTimestamp
*
* @author Gunnar Morling
*/
@ -45,4 +32,9 @@ import org.hibernate.tuple.UpdateTimestampGeneration;
@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, METHOD })
public @interface UpdateTimestamp {
/**
* Specifies how the timestamp is generated. By default, it is generated
* in memory, which saves a round trip to the database.
*/
SourceType source() default SourceType.VM;
}

View File

@ -56,6 +56,7 @@ import org.hibernate.annotations.ParamDef;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Parent;
import org.hibernate.annotations.Source;
import org.hibernate.annotations.SourceType;
import org.hibernate.annotations.TimeZoneStorage;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
@ -1800,7 +1801,8 @@ public final class AnnotationBinder {
propertyBinder.getBasicValueBinder().setVersion( true );
if ( property.isAnnotationPresent( Source.class ) ) {
final Source source = property.getAnnotation( Source.class );
propertyBinder.getBasicValueBinder().setTimestampVersionType( source.value().typeName() );
propertyBinder.getBasicValueBinder()
.setTimestampVersionType( source.value() == SourceType.DB ? "dbtimestamp" : "timestamp" );
}
}

View File

@ -45,6 +45,7 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttrib
* @author <a href="mailto:sanne@hibernate.org">Sanne Grinovero </a>
*/
public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
protected final Object id;
protected Object[] loadedState;
protected Object version;
@ -98,13 +99,13 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
if ( status != Status.READ_ONLY ) {
this.loadedState = loadedState;
}
this.id=id;
this.rowId=rowId;
this.id = id;
this.rowId = rowId;
setCompressedValue( BooleanState.EXISTS_IN_DATABASE, existsInDatabase );
this.version=version;
this.version = version;
setCompressedValue( EnumState.LOCK_MODE, lockMode );
setCompressedValue( BooleanState.IS_BEING_REPLICATED, disableVersionIncrement );
this.persister=persister;
this.persister = persister;
this.persistenceContext = persistenceContext;
}
@ -220,6 +221,11 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
return version;
}
@Override
public void postInsert(Object version) {
this.version = version;
}
@Override
public EntityPersister getPersister() {
return persister;

View File

@ -49,6 +49,8 @@ public interface EntityEntry {
Object getVersion();
void postInsert(Object version);
EntityPersister getPersister();
/**

View File

@ -136,11 +136,11 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
final EntityKey key = source.generateEntityKey( id, persister );
persistenceContext.removeEntity( key );
if ( persister.hasCollections() ) {
new EvictVisitor(source, object).process(object, persister );
new EvictVisitor( source, object ).process( object, persister );
}
}
evictEntity(object, persister, id, source);
evictEntity( object, persister, id, source);
evictCachedCollections( persister, id, source);
final Object result = source.getLoadQueryInfluencers().fromInternalFetchProfile(
@ -157,7 +157,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
// we need to grab the version value from the entity, otherwise
// we have issues with generated-version entities that may have
// multiple actions queued during the same flush
previousVersion = persister.getVersion(object);
previousVersion = persister.getVersion( object );
}
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
@ -166,7 +166,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
source.getFactory(),
source.getTenantIdentifier()
);
final SoftLock lock = cache.lockItem(source, ck, previousVersion );
final SoftLock lock = cache.lockItem( source, ck, previousVersion );
cache.remove( source, ck );
source.getActionQueue().registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) );
}

View File

@ -1937,7 +1937,7 @@ public abstract class AbstractEntityPersister
throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
}
if ( isVersionPropertyGenerated() ) {
if ( entityMetamodel.isVersionGeneratedByDatabase() ) {
// the difficulty here is exactly what we update in order to
// force the version to be incremented in the db...
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
@ -2848,8 +2848,7 @@ public abstract class AbstractEntityPersister
}
public final boolean checkVersion(final boolean[] includeProperty) {
return includeProperty[getVersionProperty()]
|| entityMetamodel.isVersionGenerated();
return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGeneratedByDatabase();
}
public boolean useGetGeneratedKeys() {
@ -4042,7 +4041,9 @@ public abstract class AbstractEntityPersister
@Override
public boolean isVersionPropertyGenerated() {
return isVersioned() && getEntityMetamodel().isVersionGenerated();
return isVersioned()
&& ( getEntityMetamodel().isVersionGeneratedByDatabase()
|| getEntityMetamodel().isVersionGeneratedInMemory() );
}
@Override

View File

@ -198,8 +198,8 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
final boolean[] propertyLaziness = entityPersister().getPropertyLaziness();
for ( int i = 0; i < propertyLaziness.length; i++ ) {
// add also all the non lazy properties because dynamic update is false
if ( propertyLaziness[i] == false ) {
// add also all the non-lazy properties because dynamic update is false
if ( !propertyLaziness[i] ) {
attributeUpdateability[i] = true;
}
}

View File

@ -7,11 +7,15 @@
package org.hibernate.tuple;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.SourceType;
import org.hibernate.dialect.Dialect;
/**
* Value generation implementation for {@link CreationTimestamp}.
*
* @author Gunnar Morling
*
* @see org.hibernate.annotations.CurrentTimestampGeneration
*/
public class CreationTimestampGeneration implements AnnotationValueGeneration<CreationTimestamp> {
@ -19,7 +23,9 @@ public class CreationTimestampGeneration implements AnnotationValueGeneration<Cr
@Override
public void initialize(CreationTimestamp annotation, Class<?> propertyType) {
generator = TimestampGenerators.get(propertyType);
if ( annotation.source() == SourceType.VM ) {
generator = TimestampGenerators.get( propertyType );
}
}
@Override
@ -39,6 +45,11 @@ public class CreationTimestampGeneration implements AnnotationValueGeneration<Cr
@Override
public String getDatabaseGeneratedReferencedColumnValue() {
return null;
return "current_timestamp";
}
@Override
public String getDatabaseGeneratedReferencedColumnValue(Dialect dialect) {
return dialect.currentTimestamp();
}
}

View File

@ -31,7 +31,7 @@ import org.hibernate.HibernateException;
*
* @author Gunnar Morling
*/
/* package */ final class TimestampGenerators {
public final class TimestampGenerators {
private static final Map<Class<?>, ValueGenerator<?>> generators;

View File

@ -6,12 +6,16 @@
*/
package org.hibernate.tuple;
import org.hibernate.annotations.SourceType;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.dialect.Dialect;
/**
* Value generation implementation for {@link UpdateTimestamp}.
*
* @author Gunnar Morling
*
* @see org.hibernate.annotations.CurrentTimestampGeneration
*/
public class UpdateTimestampGeneration implements AnnotationValueGeneration<UpdateTimestamp> {
@ -19,7 +23,9 @@ public class UpdateTimestampGeneration implements AnnotationValueGeneration<Upda
@Override
public void initialize(UpdateTimestamp annotation, Class<?> propertyType) {
generator = TimestampGenerators.get(propertyType);
if ( annotation.source() == SourceType.VM ) {
generator = TimestampGenerators.get( propertyType );
}
}
@Override
@ -39,6 +45,11 @@ public class UpdateTimestampGeneration implements AnnotationValueGeneration<Upda
@Override
public String getDatabaseGeneratedReferencedColumnValue() {
return null;
return "current_timestamp";
}
@Override
public String getDatabaseGeneratedReferencedColumnValue(Dialect dialect) {
return dialect.currentTimestamp();
}
}

View File

@ -826,11 +826,16 @@ public class EntityMetamodel implements Serializable {
return strategy != null && strategy.getGenerationTiming() != GenerationTiming.NEVER;
}
public boolean isVersionGenerated() {
public boolean isVersionGeneratedByDatabase() {
final InDatabaseValueGenerationStrategy strategy = inDatabaseValueGenerationStrategies[ versionPropertyIndex ];
return strategy != null && strategy.getGenerationTiming() != GenerationTiming.NEVER;
}
public boolean isVersionGeneratedInMemory() {
final InMemoryValueGenerationStrategy strategy = inMemoryValueGenerationStrategies[ versionPropertyIndex ];
return strategy != null && strategy.getGenerationTiming() != GenerationTiming.NEVER;
}
public int[] getNaturalIdentifierProperties() {
return naturalIdPropertyNumbers;
}

View File

@ -9,23 +9,24 @@ package org.hibernate.type;
import java.sql.Timestamp;
import java.util.Date;
import org.hibernate.Remove;
import org.hibernate.type.descriptor.java.DbTimestampJavaType;
import org.hibernate.type.descriptor.java.JdbcTimestampJavaType;
import org.hibernate.type.descriptor.jdbc.TimestampJdbcType;
/**
* {@code dbtimestamp}: A type that maps between {@link java.sql.Types#TIMESTAMP TIMESTAMP} and {@link Timestamp}.
* It maps to the database's current timestamp, rather than the jvm's
* current timestamp.
* <p>
* Note: May/may-not cause issues on dialects which do not properly support
* a true notion of timestamp (Oracle < 8, for example, where only its DATE
* datatype is supported). Depends on the frequency of DML operations...
* A type that maps between {@link java.sql.Types#TIMESTAMP TIMESTAMP}
* and {@link Timestamp}. Maps to the SQL {@code current_timestamp},
* rather than the JVM system datetime.
*
* @author Steve Ebersole
*
* @deprecated Use {@link org.hibernate.tuple.ValueGeneration} instead
*/
@Deprecated
// Note: May/may not cause issues on dialects which do not properly support
// a true notion of timestamp (Oracle < 8, for example, where only its
// DATE datatype is supported). Depends on the frequency of DML operations.
@Deprecated(since = "6.0") @Remove
public class DbTimestampType extends AbstractSingleColumnStandardBasicType<Date> {
public static final DbTimestampType INSTANCE = new DbTimestampType();

View File

@ -14,6 +14,7 @@ import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Comparator;
import org.hibernate.Remove;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
@ -32,7 +33,7 @@ import jakarta.persistence.TemporalType;
* @author Christian Beikov
* @deprecated Use {@link org.hibernate.tuple.ValueGeneration} instead
*/
@Deprecated
@Deprecated(since="6.0") @Remove
public class DbTimestampJavaType<T> implements VersionJavaType<T>, TemporalJavaType<T> {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(