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 EntityEntry entry = session.getPersistenceContextInternal().getEntry( object );
|
||||||
final EntityPersister persister = entry.getPersister();
|
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 );
|
entry.forceLocked( object, nextVersion );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -546,6 +546,8 @@ public class ActionQueue {
|
||||||
// Execute completion actions only in transaction owner (aka parent session).
|
// Execute completion actions only in transaction owner (aka parent session).
|
||||||
if ( beforeTransactionProcesses != null ) {
|
if ( beforeTransactionProcesses != null ) {
|
||||||
beforeTransactionProcesses.beforeTransactionCompletion();
|
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.AssertionFailure;
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.action.internal.EntityIncrementVersionProcess;
|
import org.hibernate.action.internal.EntityIncrementVersionProcess;
|
||||||
import org.hibernate.action.internal.EntityVerifyVersionProcess;
|
import org.hibernate.action.internal.EntityVerifyVersionProcess;
|
||||||
import org.hibernate.classic.Lifecycle;
|
import org.hibernate.classic.Lifecycle;
|
||||||
|
@ -18,7 +17,6 @@ import org.hibernate.event.spi.PostLoadEvent;
|
||||||
import org.hibernate.event.spi.PostLoadEventListener;
|
import org.hibernate.event.spi.PostLoadEventListener;
|
||||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||||
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We do 2 things here:<ul>
|
* 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" );
|
throw new AssertionFailure( "possible non-threadsafe access to the session" );
|
||||||
}
|
}
|
||||||
|
|
||||||
final LockMode lockMode = entry.getLockMode();
|
switch ( entry.getLockMode() ) {
|
||||||
switch (lockMode) {
|
|
||||||
case PESSIMISTIC_FORCE_INCREMENT:
|
case PESSIMISTIC_FORCE_INCREMENT:
|
||||||
final EntityPersister persister = entry.getPersister();
|
final Object nextVersion = entry.getPersister()
|
||||||
final Object nextVersion = persister.forceVersionIncrement(
|
.forceVersionIncrement( entry.getId(), entry.getVersion(), false, session );
|
||||||
entry.getId(),
|
entry.forceLocked( entity, nextVersion );
|
||||||
entry.getVersion(),
|
|
||||||
session
|
|
||||||
);
|
|
||||||
entry.forceLocked(entity, nextVersion);
|
|
||||||
break;
|
break;
|
||||||
case OPTIMISTIC_FORCE_INCREMENT:
|
case OPTIMISTIC_FORCE_INCREMENT:
|
||||||
final EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess(entity);
|
session.getActionQueue().registerProcess( new EntityIncrementVersionProcess( entity ) );
|
||||||
session.getActionQueue().registerProcess(incrementVersion);
|
|
||||||
break;
|
break;
|
||||||
case OPTIMISTIC:
|
case OPTIMISTIC:
|
||||||
final EntityVerifyVersionProcess verifyVersion = new EntityVerifyVersionProcess(entity);
|
session.getActionQueue().registerProcess( new EntityVerifyVersionProcess( entity ) );
|
||||||
session.getActionQueue().registerProcess(verifyVersion);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeLoadLifecycle(event, session);
|
invokeLoadLifecycle( event, session );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void invokeLoadLifecycle(PostLoadEvent event, EventSource session) {
|
protected void invokeLoadLifecycle(PostLoadEvent event, EventSource session) {
|
||||||
if ( event.getPersister().implementsLifecycle() ) {
|
if ( event.getPersister().implementsLifecycle() ) {
|
||||||
//log.debug( "calling onLoad()" );
|
|
||||||
( (Lifecycle) event.getEntity() ).onLoad( session, event.getId() );
|
( (Lifecycle) event.getEntity() ).onLoad( session, event.getId() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class LoaderHelper {
|
||||||
if ( persister.isVersioned() && requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
|
if ( persister.isVersioned() && requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
|
||||||
// todo : should we check the current isolation mode explicitly?
|
// todo : should we check the current isolation mode explicitly?
|
||||||
Object nextVersion = persister.forceVersionIncrement(
|
Object nextVersion = persister.forceVersionIncrement(
|
||||||
entry.getId(), entry.getVersion(), session
|
entry.getId(), entry.getVersion(), false, session
|
||||||
);
|
);
|
||||||
entry.forceLocked( object, nextVersion );
|
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.mutation.spi.MutationExecutorService;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
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.CachedNaturalIdValueSource;
|
||||||
import org.hibernate.engine.spi.CascadeStyle;
|
import org.hibernate.engine.spi.CascadeStyle;
|
||||||
import org.hibernate.engine.spi.CollectionKey;
|
import org.hibernate.engine.spi.CollectionKey;
|
||||||
|
@ -1953,32 +1954,7 @@ public abstract class AbstractEntityPersister
|
||||||
return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
|
return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !isVersioned() ) {
|
final Object nextVersion = calculateNextVersion( id, currentVersion, session );
|
||||||
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() ) + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, session );
|
updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, session );
|
||||||
|
|
||||||
|
@ -2016,7 +1992,53 @@ public abstract class AbstractEntityPersister
|
||||||
return nextVersion;
|
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 ) );
|
// final Update update = new Update( getFactory().getJdbcServices().getDialect() ).setTableName( getTableName( 0 ) );
|
||||||
// if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
|
// if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
|
||||||
// update.setComment( "forced version increment" );
|
// 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;
|
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?
|
* Has the class actually been bytecode instrumented?
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -37,4 +37,13 @@ public interface UpdateCoordinator {
|
||||||
Object currentVersion,
|
Object currentVersion,
|
||||||
Object nextVersion,
|
Object nextVersion,
|
||||||
SharedSessionContractImplementor session);
|
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 );
|
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
|
@Override
|
||||||
public void coordinateUpdate(
|
public void coordinateUpdate(
|
||||||
Object entity,
|
Object entity,
|
||||||
|
@ -465,11 +478,21 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
Object version,
|
Object version,
|
||||||
Object oldVersion,
|
Object oldVersion,
|
||||||
SharedSessionContractImplementor session) {
|
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;
|
assert versionUpdateGroup != null;
|
||||||
|
|
||||||
final EntityTableMapping mutatingTableDetails = (EntityTableMapping) versionUpdateGroup.getSingleOperation().getTableDetails();
|
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();
|
final EntityVersionMapping versionMapping = entityPersister().getVersionMapping();
|
||||||
|
|
||||||
|
@ -998,6 +1021,18 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
||||||
.createExecutor( resolveUpdateVersionBatchKeyAccess( dynamicUpdate, session ), group, session );
|
.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) {
|
protected BatchKeyAccess resolveUpdateVersionBatchKeyAccess(boolean dynamicUpdate, SharedSessionContractImplementor session) {
|
||||||
if ( !dynamicUpdate
|
if ( !dynamicUpdate
|
||||||
&& session.getTransactionCoordinator() != null
|
&& session.getTransactionCoordinator() != null
|
||||||
|
|
Loading…
Reference in New Issue