Skip to content

Commit c7ed34d

Browse files
committed
HHH-16939 Optimistic and Pessimistic Force Increment Update Statements are not committed when using a batch
1 parent 58d50e2 commit c7ed34d

File tree

8 files changed

+106
-31
lines changed

8 files changed

+106
-31
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public void lock(Object id, Object version, Object object, int timeout, EventSou
4848
}
4949
final EntityEntry entry = session.getPersistenceContextInternal().getEntry( object );
5050
final EntityPersister persister = entry.getPersister();
51-
final Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
51+
final Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), false, session );
5252
entry.forceLocked( object, nextVersion );
5353
}
5454

hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,8 @@ public void beforeTransactionCompletion() {
542542
// Execute completion actions only in transaction owner (aka parent session).
543543
if ( beforeTransactionProcesses != null ) {
544544
beforeTransactionProcesses.beforeTransactionCompletion();
545+
// `beforeTransactionCompletion()` can have added batch operations (e.g. to increment entity version)
546+
session.getJdbcCoordinator().executeBatch();
545547
}
546548
}
547549
}

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void onPostLoad(PostLoadEvent event) {
5151
switch ( entry.getLockMode() ) {
5252
case PESSIMISTIC_FORCE_INCREMENT:
5353
final Object nextVersion = entry.getPersister()
54-
.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
54+
.forceVersionIncrement( entry.getId(), entry.getVersion(), false, session );
5555
entry.forceLocked( entity, nextVersion );
5656
break;
5757
case OPTIMISTIC_FORCE_INCREMENT:

hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public static void upgradeLock(Object object, EntityEntry entry, LockOptions loc
8686
if ( persister.isVersioned() && requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
8787
// todo : should we check the current isolation mode explicitly?
8888
Object nextVersion = persister.forceVersionIncrement(
89-
entry.getId(), entry.getVersion(), session
89+
entry.getId(), entry.getVersion(), false, session
9090
);
9191
entry.forceLocked( object, nextVersion );
9292
}

hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,32 +2004,7 @@ public Object forceVersionIncrement(Object id, Object currentVersion, SharedSess
20042004
return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
20052005
}
20062006

2007-
if ( !isVersioned() ) {
2008-
throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
2009-
}
2010-
2011-
if ( isVersionGeneratedOnExecution() ) {
2012-
// the difficulty here is exactly what we update in order to
2013-
// force the version to be incremented in the db...
2014-
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
2015-
2016-
}
2017-
2018-
final EntityVersionMapping versionMapping = getVersionMapping();
2019-
final Object nextVersion = getVersionJavaType().next(
2020-
currentVersion,
2021-
versionMapping.getLength(),
2022-
versionMapping.getPrecision(),
2023-
versionMapping.getScale(),
2024-
session
2025-
);
2026-
if ( LOG.isTraceEnabled() ) {
2027-
LOG.trace(
2028-
"Forcing version increment [" + infoString( this, id, getFactory() ) + "; "
2029-
+ getVersionType().toLoggableString( currentVersion, getFactory() ) + " -> "
2030-
+ getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
2031-
);
2032-
}
2007+
final Object nextVersion = calculateNextVersion( id, currentVersion, session );
20332008

20342009
updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, session );
20352010

@@ -2067,7 +2042,53 @@ public Object forceVersionIncrement(Object id, Object currentVersion, SharedSess
20672042
return nextVersion;
20682043
}
20692044

2070-
// private String generateVersionIncrementUpdateString() {
2045+
@Override
2046+
public Object forceVersionIncrement(
2047+
Object id,
2048+
Object currentVersion,
2049+
boolean batching,
2050+
SharedSessionContractImplementor session) throws HibernateException {
2051+
if ( superMappingType != null ) {
2052+
return superMappingType.getEntityPersister().forceVersionIncrement( id, currentVersion, session );
2053+
}
2054+
2055+
final Object nextVersion = calculateNextVersion( id, currentVersion, session );
2056+
2057+
updateCoordinator.forceVersionIncrement( id, currentVersion, nextVersion, batching, session );
2058+
return nextVersion;
2059+
}
2060+
2061+
private Object calculateNextVersion(Object id, Object currentVersion, SharedSessionContractImplementor session) {
2062+
if ( !isVersioned() ) {
2063+
throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
2064+
}
2065+
2066+
if ( isVersionGeneratedOnExecution() ) {
2067+
// the difficulty here is exactly what we update in order to
2068+
// force the version to be incremented in the db...
2069+
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
2070+
2071+
}
2072+
2073+
final EntityVersionMapping versionMapping = getVersionMapping();
2074+
final Object nextVersion = getVersionJavaType().next(
2075+
currentVersion,
2076+
versionMapping.getLength(),
2077+
versionMapping.getPrecision(),
2078+
versionMapping.getScale(),
2079+
session
2080+
);
2081+
if ( LOG.isTraceEnabled() ) {
2082+
LOG.trace(
2083+
"Forcing version increment [" + infoString( this, id, getFactory() ) + "; "
2084+
+ getVersionType().toLoggableString( currentVersion, getFactory() ) + " -> "
2085+
+ getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
2086+
);
2087+
}
2088+
return nextVersion;
2089+
}
2090+
2091+
// private String generateVersionIncrementUpdateString() {
20712092
// final Update update = new Update( getFactory().getJdbcServices().getDialect() ).setTableName( getTableName( 0 ) );
20722093
// if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
20732094
// update.setComment( "forced version increment" );

hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,14 @@ default boolean isBatchLoadable() {
807807

808808
Object forceVersionIncrement(Object id, Object currentVersion, SharedSessionContractImplementor session) throws HibernateException;
809809

810+
default Object forceVersionIncrement(
811+
Object id,
812+
Object currentVersion,
813+
boolean batching,
814+
SharedSessionContractImplementor session) throws HibernateException {
815+
return forceVersionIncrement( id, currentVersion, session );
816+
}
817+
810818
/**
811819
* Has the class actually been bytecode instrumented?
812820
*/

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,13 @@ void forceVersionIncrement(
3737
Object currentVersion,
3838
Object nextVersion,
3939
SharedSessionContractImplementor session);
40+
41+
default void forceVersionIncrement(
42+
Object id,
43+
Object currentVersion,
44+
Object nextVersion,
45+
boolean batching,
46+
SharedSessionContractImplementor session){
47+
forceVersionIncrement( id, currentVersion, nextVersion, session );
48+
}
4049
}

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,19 @@ public void forceVersionIncrement(
153153
doVersionUpdate( null, id, nextVersion, currentVersion, session );
154154
}
155155

156+
@Override
157+
public void forceVersionIncrement(
158+
Object id,
159+
Object currentVersion,
160+
Object nextVersion,
161+
boolean batching,
162+
SharedSessionContractImplementor session) {
163+
if ( versionUpdateGroup == null ) {
164+
throw new HibernateException( "Cannot force version increment relative to sub-type; use the root type" );
165+
}
166+
doVersionUpdate( null, id, nextVersion, currentVersion, batching, session );
167+
}
168+
156169
@Override
157170
public void coordinateUpdate(
158171
Object entity,
@@ -466,11 +479,21 @@ protected void doVersionUpdate(
466479
Object version,
467480
Object oldVersion,
468481
SharedSessionContractImplementor session) {
482+
doVersionUpdate( entity, id, version, oldVersion, true, session );
483+
}
484+
485+
protected void doVersionUpdate(
486+
Object entity,
487+
Object id,
488+
Object version,
489+
Object oldVersion,
490+
boolean batching,
491+
SharedSessionContractImplementor session) {
469492
assert versionUpdateGroup != null;
470493

471494
final EntityTableMapping mutatingTableDetails = (EntityTableMapping) versionUpdateGroup.getSingleOperation().getTableDetails();
472495

473-
final MutationExecutor mutationExecutor = updateVersionExecutor( session, versionUpdateGroup, false );
496+
final MutationExecutor mutationExecutor = updateVersionExecutor( session, versionUpdateGroup, false, batching );
474497

475498
final EntityVersionMapping versionMapping = entityPersister().getVersionMapping();
476499

@@ -1001,6 +1024,18 @@ private MutationExecutor updateVersionExecutor(SharedSessionContractImplementor
10011024
.createExecutor( resolveUpdateVersionBatchKeyAccess( dynamicUpdate, session ), group, session );
10021025
}
10031026

1027+
private MutationExecutor updateVersionExecutor(
1028+
SharedSessionContractImplementor session,
1029+
MutationOperationGroup group,
1030+
boolean dynamicUpdate,
1031+
boolean batching) {
1032+
if ( batching ) {
1033+
return updateVersionExecutor(session, group,dynamicUpdate);
1034+
}
1035+
return mutationExecutorService.createExecutor( NoBatchKeyAccess.INSTANCE, group, session );
1036+
1037+
}
1038+
10041039
protected BatchKeyAccess resolveUpdateVersionBatchKeyAccess(boolean dynamicUpdate, SharedSessionContractImplementor session) {
10051040
if ( !dynamicUpdate
10061041
&& session.getTransactionCoordinator() != null

0 commit comments

Comments
 (0)