HHH-16939 Optimistic and Pessimistic Force Increment Update Statements are not committed when using a batch

This commit is contained in:
Andrea Boriero 2023-07-24 22:01:51 +02:00 committed by Andrea Boriero
parent 58d50e26f7
commit c7ed34d159
8 changed files with 106 additions and 31 deletions

View File

@ -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 );
}

View File

@ -542,6 +542,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();
}
}
}

View File

@ -51,7 +51,7 @@ public class DefaultPostLoadEventListener implements PostLoadEventListener, Call
switch ( entry.getLockMode() ) {
case PESSIMISTIC_FORCE_INCREMENT:
final Object nextVersion = entry.getPersister()
.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
.forceVersionIncrement( entry.getId(), entry.getVersion(), false, session );
entry.forceLocked( entity, nextVersion );
break;
case OPTIMISTIC_FORCE_INCREMENT:

View File

@ -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 );
}

View File

@ -2004,32 +2004,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 );
@ -2067,7 +2042,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" );

View File

@ -807,6 +807,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?
*/

View File

@ -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 );
}
}

View File

@ -153,6 +153,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,
@ -466,11 +479,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();
@ -1001,6 +1024,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