HHH-16939 Optimistic and Pessimistic Force Increment Update Statements are not committed when using a batch
This commit is contained in:
parent
6cc1f1f9e6
commit
c0189c0bd4
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:<ul>
|
||||
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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?
|
||||
*/
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue