diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java
index 13c79b0c59..287c038463 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java
@@ -48,7 +48,7 @@ public class PessimisticForceIncrementLockingStrategy implements LockingStrategy
}
final EntityEntry entry = session.getPersistenceContextInternal().getEntry( object );
final EntityPersister persister = entry.getPersister();
- final Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
+ final Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), false, session );
entry.forceLocked( object, nextVersion );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
index be4f39f782..b5567e47cc 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
@@ -546,6 +546,8 @@ public class ActionQueue {
// Execute completion actions only in transaction owner (aka parent session).
if ( beforeTransactionProcesses != null ) {
beforeTransactionProcesses.beforeTransactionCompletion();
+ // `beforeTransactionCompletion()` can have added batch operations (e.g. to increment entity version)
+ session.getJdbcCoordinator().executeBatch();
}
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java
index c1006d290c..70b51e943e 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java
@@ -8,7 +8,6 @@ package org.hibernate.event.internal;
import org.hibernate.AssertionFailure;
-import org.hibernate.LockMode;
import org.hibernate.action.internal.EntityIncrementVersionProcess;
import org.hibernate.action.internal.EntityVerifyVersionProcess;
import org.hibernate.classic.Lifecycle;
@@ -18,7 +17,6 @@ import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
-import org.hibernate.persister.entity.EntityPersister;
/**
* We do 2 things here:
@@ -49,34 +47,26 @@ public class DefaultPostLoadEventListener implements PostLoadEventListener, Call
throw new AssertionFailure( "possible non-threadsafe access to the session" );
}
- final LockMode lockMode = entry.getLockMode();
- switch (lockMode) {
+ switch ( entry.getLockMode() ) {
case PESSIMISTIC_FORCE_INCREMENT:
- final EntityPersister persister = entry.getPersister();
- final Object nextVersion = persister.forceVersionIncrement(
- entry.getId(),
- entry.getVersion(),
- session
- );
- entry.forceLocked(entity, nextVersion);
+ final Object nextVersion = entry.getPersister()
+ .forceVersionIncrement( entry.getId(), entry.getVersion(), false, session );
+ entry.forceLocked( entity, nextVersion );
break;
case OPTIMISTIC_FORCE_INCREMENT:
- final EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess(entity);
- session.getActionQueue().registerProcess(incrementVersion);
+ session.getActionQueue().registerProcess( new EntityIncrementVersionProcess( entity ) );
break;
case OPTIMISTIC:
- final EntityVerifyVersionProcess verifyVersion = new EntityVerifyVersionProcess(entity);
- session.getActionQueue().registerProcess(verifyVersion);
+ session.getActionQueue().registerProcess( new EntityVerifyVersionProcess( entity ) );
break;
}
- invokeLoadLifecycle(event, session);
+ invokeLoadLifecycle( event, session );
}
protected void invokeLoadLifecycle(PostLoadEvent event, EventSource session) {
if ( event.getPersister().implementsLifecycle() ) {
- //log.debug( "calling onLoad()" );
( (Lifecycle) event.getEntity() ).onLoad( session, event.getId() );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderHelper.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderHelper.java
index 3664ef38e4..ec78f2b901 100644
--- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderHelper.java
@@ -86,7 +86,7 @@ public class LoaderHelper {
if ( persister.isVersioned() && requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
// todo : should we check the current isolation mode explicitly?
Object nextVersion = persister.forceVersionIncrement(
- entry.getId(), entry.getVersion(), session
+ entry.getId(), entry.getVersion(), false, session
);
entry.forceLocked( object, nextVersion );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
index e115019efb..1bd3247016 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
@@ -79,6 +79,7 @@ import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
+import org.hibernate.engine.profile.internal.FetchProfileAffectee;
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CollectionKey;
@@ -1953,32 +1954,7 @@ public abstract class AbstractEntityPersister
return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
}
- if ( !isVersioned() ) {
- throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
- }
-
- if ( isVersionGeneratedOnExecution() ) {
- // 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" );
-
- }
-
- final EntityVersionMapping versionMapping = getVersionMapping();
- final Object nextVersion = getVersionJavaType().next(
- currentVersion,
- versionMapping.getLength(),
- versionMapping.getPrecision(),
- versionMapping.getScale(),
- session
- );
- if ( LOG.isTraceEnabled() ) {
- LOG.trace(
- "Forcing version increment [" + infoString( this, id, getFactory() ) + "; "
- + getVersionType().toLoggableString( currentVersion, getFactory() ) + " -> "
- + getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
- );
- }
+ final Object nextVersion = calculateNextVersion( id, currentVersion, session );
updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, session );
@@ -2016,7 +1992,53 @@ public abstract class AbstractEntityPersister
return nextVersion;
}
-// private String generateVersionIncrementUpdateString() {
+ @Override
+ public Object forceVersionIncrement(
+ Object id,
+ Object currentVersion,
+ boolean batching,
+ SharedSessionContractImplementor session) throws HibernateException {
+ if ( superMappingType != null ) {
+ return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
+ }
+
+ final Object nextVersion = calculateNextVersion( id, currentVersion, session );
+
+ updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, batching, session );
+ return nextVersion;
+ }
+
+ private Object calculateNextVersion(Object id, Object currentVersion, SharedSessionContractImplementor session) {
+ if ( !isVersioned() ) {
+ throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
+ }
+
+ if ( isVersionGeneratedOnExecution() ) {
+ // 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" );
+
+ }
+
+ final EntityVersionMapping versionMapping = getVersionMapping();
+ final Object nextVersion = getVersionJavaType().next(
+ currentVersion,
+ versionMapping.getLength(),
+ versionMapping.getPrecision(),
+ versionMapping.getScale(),
+ session
+ );
+ if ( LOG.isTraceEnabled() ) {
+ LOG.trace(
+ "Forcing version increment [" + infoString( this, id, getFactory() ) + "; "
+ + getVersionType().toLoggableString( currentVersion, getFactory() ) + " -> "
+ + getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
+ );
+ }
+ return nextVersion;
+ }
+
+ // private String generateVersionIncrementUpdateString() {
// final Update update = new Update( getFactory().getJdbcServices().getDialect() ).setTableName( getTableName( 0 ) );
// if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
// update.setComment( "forced version increment" );
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
index f3239605aa..23d54c938c 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
@@ -777,6 +777,14 @@ public interface EntityPersister extends EntityMappingType, RootTableGroupProduc
Object forceVersionIncrement(Object id, Object currentVersion, SharedSessionContractImplementor session) throws HibernateException;
+ default Object forceVersionIncrement(
+ Object id,
+ Object currentVersion,
+ boolean batching,
+ SharedSessionContractImplementor session) throws HibernateException {
+ return forceVersionIncrement( id, currentVersion, session );
+ }
+
/**
* Has the class actually been bytecode instrumented?
*/
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java
index 2f766b0960..54bd749949 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java
@@ -37,4 +37,13 @@ public interface UpdateCoordinator {
Object currentVersion,
Object nextVersion,
SharedSessionContractImplementor session);
+
+ default void forceVersionIncrement(
+ Object id,
+ Object currentVersion,
+ Object nextVersion,
+ boolean batching,
+ SharedSessionContractImplementor session){
+ forceVersionIncrement( id, currentVersion, nextVersion, session );
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java
index b0a0cc02fe..541f2a1422 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java
@@ -152,6 +152,19 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
doVersionUpdate( null, id, nextVersion, currentVersion, session );
}
+ @Override
+ public void forceVersionIncrement(
+ Object id,
+ Object currentVersion,
+ Object nextVersion,
+ boolean batching,
+ SharedSessionContractImplementor session) {
+ if ( versionUpdateGroup == null ) {
+ throw new HibernateException( "Cannot force version increment relative to sub-type; use the root type" );
+ }
+ doVersionUpdate( null, id, nextVersion, currentVersion, batching, session );
+ }
+
@Override
public void coordinateUpdate(
Object entity,
@@ -465,11 +478,21 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
Object version,
Object oldVersion,
SharedSessionContractImplementor session) {
+ doVersionUpdate( entity, id, version, oldVersion, true, session );
+ }
+
+ protected void doVersionUpdate(
+ Object entity,
+ Object id,
+ Object version,
+ Object oldVersion,
+ boolean batching,
+ SharedSessionContractImplementor session) {
assert versionUpdateGroup != null;
final EntityTableMapping mutatingTableDetails = (EntityTableMapping) versionUpdateGroup.getSingleOperation().getTableDetails();
- final MutationExecutor mutationExecutor = updateVersionExecutor( session, versionUpdateGroup, false );
+ final MutationExecutor mutationExecutor = updateVersionExecutor( session, versionUpdateGroup, false, batching );
final EntityVersionMapping versionMapping = entityPersister().getVersionMapping();
@@ -998,6 +1021,18 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
.createExecutor( resolveUpdateVersionBatchKeyAccess( dynamicUpdate, session ), group, session );
}
+ private MutationExecutor updateVersionExecutor(
+ SharedSessionContractImplementor session,
+ MutationOperationGroup group,
+ boolean dynamicUpdate,
+ boolean batching) {
+ if ( batching ) {
+ return updateVersionExecutor(session, group,dynamicUpdate);
+ }
+ return mutationExecutorService.createExecutor( NoBatchKeyAccess.INSTANCE, group, session );
+
+ }
+
protected BatchKeyAccess resolveUpdateVersionBatchKeyAccess(boolean dynamicUpdate, SharedSessionContractImplementor session) {
if ( !dynamicUpdate
&& session.getTransactionCoordinator() != null