diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java index 0643343d14..177d8d51b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java @@ -113,7 +113,7 @@ public abstract class AbstractEntityInsertAction extends EntityAction { * @see #makeEntityManaged() */ protected final void nullifyTransientReferencesIfNotAlready() { - if ( ! areTransientReferencesNullified ) { + if ( !areTransientReferencesNullified ) { new ForeignKeys.Nullifier( getInstance(), false, isEarlyInsert(), getSession(), getPersister() ) .nullifyTransientReferences( getState() ); new Nullability( getSession() ).checkNullability( getState(), getPersister(), false ); @@ -210,28 +210,25 @@ public abstract class AbstractEntityInsertAction extends EntityAction { */ public void handleNaturalIdPostSaveNotifications(Object generatedId) { final NaturalIdMapping naturalIdMapping = getPersister().getNaturalIdMapping(); - if ( naturalIdMapping == null ) { - return; - } - - final Object naturalIdValues = naturalIdMapping.extractNaturalIdFromEntityState( state, getSession() ); - - if ( isEarlyInsert() ) { - // with early insert, we still need to add a local (transactional) natural id cross-reference - getSession().getPersistenceContextInternal().getNaturalIdResolutions().manageLocalResolution( + if ( naturalIdMapping != null ) { + final Object naturalIdValues = naturalIdMapping.extractNaturalIdFromEntityState( state, getSession() ); + if ( isEarlyInsert() ) { + // with early insert, we still need to add a local (transactional) natural id cross-reference + getSession().getPersistenceContextInternal().getNaturalIdResolutions().manageLocalResolution( + generatedId, + naturalIdValues, + getPersister(), + CachedNaturalIdValueSource.INSERT + ); + } + // after save, we need to manage the shared cache entries + getSession().getPersistenceContextInternal().getNaturalIdResolutions().manageSharedResolution( generatedId, naturalIdValues, + null, getPersister(), CachedNaturalIdValueSource.INSERT ); } - // after save, we need to manage the shared cache entries - getSession().getPersistenceContextInternal().getNaturalIdResolutions().manageSharedResolution( - generatedId, - naturalIdValues, - null, - getPersister(), - CachedNaturalIdValueSource.INSERT - ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java index c64c5d1fb8..03fd27bd99 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/BulkOperationCleanupAction.java @@ -46,6 +46,7 @@ import org.hibernate.sql.ast.tree.insert.InsertStatement; * @author Steve Ebersole */ public class BulkOperationCleanupAction implements Executable, Serializable { + private final Serializable[] affectedTableSpaces; private final Set entityCleanups = new HashSet<>(); @@ -63,7 +64,6 @@ public class BulkOperationCleanupAction implements Executable, Serializable { * @param affectedQueryables The affected entity persisters. */ public BulkOperationCleanupAction(SharedSessionContractImplementor session, EntityPersister... affectedQueryables) { - final SessionFactoryImplementor factory = session.getFactory(); final LinkedHashSet spacesList = new LinkedHashSet<>(); for ( EntityPersister persister : affectedQueryables ) { Collections.addAll( spacesList, (String[]) persister.getQuerySpaces() ); @@ -81,17 +81,14 @@ public class BulkOperationCleanupAction implements Executable, Serializable { ); } - final MappingMetamodelImplementor mappingMetamodel = factory.getRuntimeMetamodels().getMappingMetamodel(); + final MappingMetamodelImplementor mappingMetamodel = session.getFactory().getRuntimeMetamodels().getMappingMetamodel(); final Set roles = mappingMetamodel.getCollectionRolesByEntityParticipant( persister.getEntityName() ); if ( roles != null ) { for ( String role : roles ) { final CollectionPersister collectionPersister = mappingMetamodel.getCollectionDescriptor( role ); if ( collectionPersister.hasCache() ) { collectionCleanups.add( - new CollectionCleanup( - collectionPersister.getCacheAccessStrategy(), - session - ) + new CollectionCleanup( collectionPersister.getCacheAccessStrategy(), session ) ); } } @@ -103,11 +100,12 @@ public class BulkOperationCleanupAction implements Executable, Serializable { /** * Constructs an action to cleanup "affected cache regions" based on a - * set of affected table spaces. This differs from {@link #BulkOperationCleanupAction(SharedSessionContractImplementor, EntityPersister[])} - * in that here we have the affected table names. From those - * we deduce the entity persisters which are affected based on the defined - * {@link EntityPersister#getQuerySpaces() table spaces}; and from there, we - * determine the affected collection regions based on any collections + * set of affected table spaces. This differs from + * {@link #BulkOperationCleanupAction(SharedSessionContractImplementor, EntityPersister[])} + * in that here we have the affected table names. From + * those we deduce the entity persisters which are affected based on the + * defined {@link EntityPersister#getQuerySpaces() table spaces}. Finally, + * we determine the affected collection regions based on any collections * in which those entity persisters participate as elements/keys/etc. * * @param session The session to which this request is tied. @@ -116,8 +114,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable { public BulkOperationCleanupAction(SharedSessionContractImplementor session, Set tableSpaces) { final LinkedHashSet spacesList = new LinkedHashSet<>( tableSpaces ); - final SessionFactoryImplementor factory = session.getFactory(); - final MappingMetamodelImplementor metamodel = factory.getRuntimeMetamodels().getMappingMetamodel(); + final MappingMetamodelImplementor metamodel = session.getFactory().getRuntimeMetamodels().getMappingMetamodel(); metamodel.forEachEntityDescriptor( (entityDescriptor) -> { final String[] entitySpaces = (String[]) entityDescriptor.getQuerySpaces(); if ( affectedEntity( tableSpaces, entitySpaces ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java index b4334e1342..d11522a790 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java @@ -28,6 +28,7 @@ import org.hibernate.pretty.MessageHelper; * @author Gavin King */ public abstract class CollectionAction implements Executable, Serializable, Comparable { + private transient CollectionPersister persister; private transient SharedSessionContractImplementor session; private final PersistentCollection collection; diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java index a82fa3b5a1..751853c413 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java @@ -41,7 +41,6 @@ public final class CollectionRecreateAction extends CollectionAction { // this method is called when a new non-null collection is persisted // or when an existing (non-null) collection is moved to a new owner final PersistentCollection collection = getCollection(); - preRecreate(); final SharedSessionContractImplementor session = getSession(); getPersister().recreate( collection, getKey(), session); @@ -56,9 +55,9 @@ public final class CollectionRecreateAction extends CollectionAction { } private void preRecreate() { - getFastSessionServices() - .eventListenerGroup_PRE_COLLECTION_RECREATE - .fireLazyEventOnEachListener( this::newPreCollectionRecreateEvent, PreCollectionRecreateEventListener::onPreRecreateCollection ); + getFastSessionServices().eventListenerGroup_PRE_COLLECTION_RECREATE + .fireLazyEventOnEachListener( this::newPreCollectionRecreateEvent, + PreCollectionRecreateEventListener::onPreRecreateCollection ); } private PreCollectionRecreateEvent newPreCollectionRecreateEvent() { @@ -66,9 +65,9 @@ public final class CollectionRecreateAction extends CollectionAction { } private void postRecreate() { - getFastSessionServices() - .eventListenerGroup_POST_COLLECTION_RECREATE - .fireLazyEventOnEachListener( this::newPostCollectionRecreateEvent, PostCollectionRecreateEventListener::onPostRecreateCollection ); + getFastSessionServices().eventListenerGroup_POST_COLLECTION_RECREATE + .fireLazyEventOnEachListener( this::newPostCollectionRecreateEvent, + PostCollectionRecreateEventListener::onPostRecreateCollection ); } private PostCollectionRecreateEvent newPostCollectionRecreateEvent() { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java index bde8e19e89..d9a596442a 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java @@ -21,6 +21,7 @@ import org.hibernate.stat.spi.StatisticsImplementor; * The action for removing a collection */ public final class CollectionRemoveAction extends CollectionAction { + private final Object affectedOwner; private final boolean emptySnapshot; @@ -101,9 +102,7 @@ public final class CollectionRemoveAction extends CollectionAction { @Override public void execute() throws HibernateException { preRemove(); - final SharedSessionContractImplementor session = getSession(); - if ( !emptySnapshot ) { // an existing collection that was either nonempty or uninitialized // is replaced by null or a different collection @@ -111,12 +110,10 @@ public final class CollectionRemoveAction extends CollectionAction { // knowing if the collection is actually empty without querying the db) getPersister().remove( getKey(), session ); } - final PersistentCollection collection = getCollection(); if ( collection != null ) { session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection ); } - evict(); postRemove(); @@ -127,9 +124,9 @@ public final class CollectionRemoveAction extends CollectionAction { } private void preRemove() { - getFastSessionServices() - .eventListenerGroup_PRE_COLLECTION_REMOVE - .fireLazyEventOnEachListener( this::newPreCollectionRemoveEvent, PreCollectionRemoveEventListener::onPreRemoveCollection ); + getFastSessionServices().eventListenerGroup_PRE_COLLECTION_REMOVE + .fireLazyEventOnEachListener( this::newPreCollectionRemoveEvent, + PreCollectionRemoveEventListener::onPreRemoveCollection ); } private PreCollectionRemoveEvent newPreCollectionRemoveEvent() { @@ -142,9 +139,9 @@ public final class CollectionRemoveAction extends CollectionAction { } private void postRemove() { - getFastSessionServices() - .eventListenerGroup_POST_COLLECTION_REMOVE - .fireLazyEventOnEachListener( this::newPostCollectionRemoveEvent, PostCollectionRemoveEventListener::onPostRemoveCollection ); + getFastSessionServices().eventListenerGroup_POST_COLLECTION_REMOVE + .fireLazyEventOnEachListener( this::newPostCollectionRemoveEvent, + PostCollectionRemoveEventListener::onPostRemoveCollection ); } private PostCollectionRemoveEvent newPostCollectionRemoveEvent() { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java index 290134c84f..60193b422d 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java @@ -22,6 +22,7 @@ import org.hibernate.stat.spi.StatisticsImplementor; * The action for updating a collection */ public final class CollectionUpdateAction extends CollectionAction { + private final boolean emptySnapshot; /** @@ -68,9 +69,8 @@ public final class CollectionUpdateAction extends CollectionAction { } else if ( collection.needsRecreate( persister ) ) { if ( affectedByFilters ) { - throw new HibernateException( - "cannot recreate collection while filter is enabled: " + - MessageHelper.collectionInfoString( persister, collection, id, session ) + throw new HibernateException( "cannot recreate collection while filter is enabled: " + + MessageHelper.collectionInfoString( persister, collection, id, session ) ); } if ( !emptySnapshot ) { @@ -95,9 +95,9 @@ public final class CollectionUpdateAction extends CollectionAction { } private void preUpdate() { - getFastSessionServices() - .eventListenerGroup_PRE_COLLECTION_UPDATE - .fireLazyEventOnEachListener( this::newPreCollectionUpdateEvent, PreCollectionUpdateEventListener::onPreUpdateCollection ); + getFastSessionServices().eventListenerGroup_PRE_COLLECTION_UPDATE + .fireLazyEventOnEachListener( this::newPreCollectionUpdateEvent, + PreCollectionUpdateEventListener::onPreUpdateCollection ); } private PreCollectionUpdateEvent newPreCollectionUpdateEvent() { @@ -109,9 +109,9 @@ public final class CollectionUpdateAction extends CollectionAction { } private void postUpdate() { - getFastSessionServices() - .eventListenerGroup_POST_COLLECTION_UPDATE - .fireLazyEventOnEachListener( this::newPostCollectionUpdateEvent, PostCollectionUpdateEventListener::onPostUpdateCollection ); + getFastSessionServices().eventListenerGroup_POST_COLLECTION_UPDATE + .fireLazyEventOnEachListener( this::newPostCollectionUpdateEvent, + PostCollectionUpdateEventListener::onPostUpdateCollection ); } private PostCollectionUpdateEvent newPostCollectionUpdateEvent() { diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java index 86ed867426..12d83de51e 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java @@ -106,9 +106,7 @@ public abstract class EntityAction } public final DelayedPostInsertIdentifier getDelayedId() { - return id instanceof DelayedPostInsertIdentifier - ? (DelayedPostInsertIdentifier) id - : null; + return id instanceof DelayedPostInsertIdentifier ? (DelayedPostInsertIdentifier) id : null; } /** @@ -157,13 +155,9 @@ public abstract class EntityAction public int compareTo(EntityAction action) { //sort first by entity name final int roleComparison = entityName.compareTo( action.entityName ); - if ( roleComparison != 0 ) { - return roleComparison; - } - else { - //then by id - return persister.getIdentifierType().compare( id, action.id ); - } + return roleComparison != 0 ? roleComparison + //then by id + : persister.getIdentifierType().compare( id, action.id ); } /** @@ -180,7 +174,7 @@ public abstract class EntityAction // guard against NullPointerException if ( session != null ) { this.session = session; - this.persister = session.getFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor( entityName ); + this.persister = session.getFactory().getMappingMetamodel().getEntityDescriptor( entityName ); this.instance = session.getPersistenceContext().getEntity( session.generateEntityKey( id, persister ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index 1d7c00f661..c8d0de34b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -61,7 +61,7 @@ public class EntityDeleteAction extends EntityAction { this.isCascadeDeleteEnabled = isCascadeDeleteEnabled; this.state = state; - NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping(); + final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping(); if ( naturalIdMapping != null ) { naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions() .removeLocalResolution( @@ -79,10 +79,7 @@ public class EntityDeleteAction extends EntityAction { * @param persister The entity persister * @param session The session */ - public EntityDeleteAction( - final Object id, - final EntityPersister persister, - final SessionImplementor session) { + public EntityDeleteAction(final Object id, final EntityPersister persister, final SessionImplementor session) { super( session, id, null, persister ); version = null; isCascadeDeleteEnabled = false; @@ -128,15 +125,7 @@ public class EntityDeleteAction extends EntityAction { final boolean veto = isInstanceLoaded() && preDelete(); - final Object ck; - if ( persister.canWriteToCache() ) { - final EntityDataAccess cache = persister.getCacheAccessStrategy(); - ck = cache.generateCacheKey( id, persister, session.getFactory(), session.getTenantIdentifier() ); - lock = cache.lockItem( session, ck, version ); - } - else { - ck = null; - } + final Object ck = lockCacheItem(); if ( !isCascadeDeleteEnabled && !veto ) { persister.delete( id, version, instance, session ); @@ -182,17 +171,11 @@ public class EntityDeleteAction extends EntityAction { throw new AssertionFailure( "possible non-threadsafe access to session" ); } entry.postDelete(); - EntityKey key = entry.getEntityKey(); persistenceContext.removeEntity( key ); persistenceContext.removeProxy( key ); - - if ( persister.canWriteToCache() ) { - persister.getCacheAccessStrategy().remove( session, ck ); - } - + removeCacheItem( ck ); persistenceContext.getNaturalIdResolutions().removeSharedResolution( id, naturalIdValues, persister ); - postDelete(); } @@ -203,27 +186,27 @@ public class EntityDeleteAction extends EntityAction { throw new AssertionFailure( "deleted proxy should be for an unloaded entity: " + key ); } persistenceContext.removeProxy( key ); - if ( persister.canWriteToCache() ) { - persister.getCacheAccessStrategy().remove( session, ck ); - } + removeCacheItem( ck ); } protected boolean preDelete() { - final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_DELETE; + final EventListenerGroup listenerGroup + = getFastSessionServices().eventListenerGroup_PRE_DELETE; if ( listenerGroup.isEmpty() ) { return false; } - final PreDeleteEvent event = new PreDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() ); - boolean veto = false; - for ( PreDeleteEventListener listener : listenerGroup.listeners() ) { - veto |= listener.onPreDelete( event ); + else { + final PreDeleteEvent event = new PreDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() ); + boolean veto = false; + for ( PreDeleteEventListener listener : listenerGroup.listeners() ) { + veto |= listener.onPreDelete( event ); + } + return veto; } - return veto; } protected void postDelete() { - getFastSessionServices() - .eventListenerGroup_POST_DELETE + getFastSessionServices().eventListenerGroup_POST_DELETE .fireLazyEventOnEachListener( this::newPostDeleteEvent, PostDeleteEventListener::onPostDelete ); } @@ -238,8 +221,8 @@ public class EntityDeleteAction extends EntityAction { } protected void postCommitDelete(boolean success) { - final EventListenerGroup eventListeners = getFastSessionServices() - .eventListenerGroup_POST_COMMIT_DELETE; + final EventListenerGroup eventListeners + = getFastSessionServices().eventListenerGroup_POST_COMMIT_DELETE; if (success) { eventListeners.fireLazyEventOnEachListener( this::newPostDeleteEvent, PostDeleteEventListener::onPostDelete ); } @@ -260,29 +243,53 @@ public class EntityDeleteAction extends EntityAction { @Override public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException { - EntityPersister entityPersister = getPersister(); - if ( entityPersister.canWriteToCache() ) { - EntityDataAccess cache = entityPersister.getCacheAccessStrategy(); - final Object ck = cache.generateCacheKey( - getId(), - entityPersister, - session.getFactory(), - session.getTenantIdentifier() - ); - cache.unlockItem( session, ck, lock ); - } + unlockCacheItem(); postCommitDelete( success ); } @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_DELETE; - for ( PostDeleteEventListener listener : group.listeners() ) { + for ( PostDeleteEventListener listener: getFastSessionServices().eventListenerGroup_POST_COMMIT_DELETE.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; } } - return false; } + + private Object lockCacheItem() { + final EntityPersister persister = getPersister(); + if ( persister.canWriteToCache() ) { + final EntityDataAccess cache = persister.getCacheAccessStrategy(); + final SharedSessionContractImplementor session = getSession(); + Object ck = cache.generateCacheKey( getId(), persister, session.getFactory(), session.getTenantIdentifier() ); + lock = cache.lockItem( session, ck, getCurrentVersion() ); + return ck; + } + else { + return null; + } + } + + private void unlockCacheItem() { + final EntityPersister persister = getPersister(); + if ( persister.canWriteToCache() ) { + final EntityDataAccess cache = persister.getCacheAccessStrategy(); + final SharedSessionContractImplementor session = getSession(); + final Object ck = cache.generateCacheKey( + getId(), + persister, + session.getFactory(), + session.getTenantIdentifier() + ); + cache.unlockItem( session, ck, lock ); + } + } + + private void removeCacheItem(Object ck) { + final EntityPersister persister = getPersister(); + if ( persister.canWriteToCache() ) { + persister.getCacheAccessStrategy().remove( getSession(), ck ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java index 47cd844764..077511ec89 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java @@ -45,12 +45,12 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { * @throws HibernateException Indicates an illegal state */ public EntityIdentityInsertAction( - Object[] state, - Object instance, - EntityPersister persister, - boolean isVersionIncrementDisabled, - SharedSessionContractImplementor session, - boolean isDelayed) { + final Object[] state, + final Object instance, + final EntityPersister persister, + final boolean isVersionIncrementDisabled, + final SharedSessionContractImplementor session, + final boolean isDelayed) { super( isDelayed ? generateDelayedPostInsertIdentifier() : null, state, @@ -90,7 +90,6 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { persistenceContext.checkUniqueness( entityKey, getInstance() ); } - //TODO: this bit actually has to be called after all cascades! // but since identity insert is called *synchronously*, // instead of asynchronously as other actions, it isn't @@ -117,13 +116,13 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT; + final EventListenerGroup group + = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT; for ( PostInsertEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; } } - return false; } @@ -139,10 +138,10 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { protected void postInsert() { if ( isDelayed ) { - eventSource().getPersistenceContextInternal().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId ); + eventSource().getPersistenceContextInternal() + .replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId ); } - getFastSessionServices() - .eventListenerGroup_POST_INSERT + getFastSessionServices().eventListenerGroup_POST_INSERT .fireLazyEventOnEachListener( this::newPostInsertEvent, PostInsertEventListener::onPostInsert ); } @@ -157,9 +156,9 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { } protected void postCommitInsert(boolean success) { - getFastSessionServices() - .eventListenerGroup_POST_COMMIT_INSERT - .fireLazyEventOnEachListener( this::newPostInsertEvent, success ? PostInsertEventListener::onPostInsert : this::postCommitInsertOnFailure ); + getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT + .fireLazyEventOnEachListener( this::newPostInsertEvent, + success ? PostInsertEventListener::onPostInsert : this::postCommitInsertOnFailure ); } private void postCommitInsertOnFailure(PostInsertEventListener listener, PostInsertEvent event) { @@ -173,17 +172,20 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { } protected boolean preInsert() { - final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_INSERT; + final EventListenerGroup listenerGroup + = getFastSessionServices().eventListenerGroup_PRE_INSERT; if ( listenerGroup.isEmpty() ) { // NO_VETO return false; } - boolean veto = false; - final PreInsertEvent event = new PreInsertEvent( getInstance(), null, getState(), getPersister(), eventSource() ); - for ( PreInsertEventListener listener : listenerGroup.listeners() ) { - veto |= listener.onPreInsert( event ); + else { + final PreInsertEvent event = new PreInsertEvent( getInstance(), null, getState(), getPersister(), eventSource() ); + boolean veto = false; + for ( PreInsertEventListener listener : listenerGroup.listeners() ) { + veto |= listener.onPreInsert( event ); + } + return veto; } - return veto; } /** @@ -218,9 +220,11 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { } protected EntityKey generateDelayedEntityKey() { - if ( !isDelayed ) { + if ( isDelayed ) { + return getSession().generateEntityKey( getDelayedId(), getPersister() ); + } + else { throw new AssertionFailure( "cannot request delayed entity-key for early-insert post-insert-id generation" ); } - return getSession().generateEntityKey( getDelayedId(), getPersister() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index fe9c1d51b1..8d9daa4d95 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -33,6 +33,7 @@ import org.hibernate.stat.spi.StatisticsImplementor; * @see EntityIdentityInsertAction */ public class EntityInsertAction extends AbstractEntityInsertAction { + private Object version; private Object cacheEntry; @@ -47,13 +48,13 @@ public class EntityInsertAction extends AbstractEntityInsertAction { * @param session The session */ public EntityInsertAction( - Object id, - Object[] state, - Object instance, - Object version, - EntityPersister persister, - boolean isVersionIncrementDisabled, - SharedSessionContractImplementor session) { + final Object id, + final Object[] state, + final Object instance, + final Object version, + final EntityPersister persister, + final boolean isVersionIncrementDisabled, + final SharedSessionContractImplementor session) { super( id, state, instance, isVersionIncrementDisabled, persister, session ); this.version = version; } @@ -88,67 +89,31 @@ public class EntityInsertAction extends AbstractEntityInsertAction { public void execute() throws HibernateException { nullifyTransientReferencesIfNotAlready(); - final EntityPersister persister = getPersister(); - final SharedSessionContractImplementor session = getSession(); - final Object instance = getInstance(); - final Object id = getId(); - - final boolean veto = preInsert(); - // Don't need to lock the cache here, since if someone // else inserted the same pk first, the insert would fail + final SharedSessionContractImplementor session = getSession(); + final Object id = getId(); + final boolean veto = preInsert(); if ( !veto ) { - + final EntityPersister persister = getPersister(); + final Object instance = getInstance(); persister.insert( id, getState(), instance, session ); PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityEntry entry = persistenceContext.getEntry( instance ); if ( entry == null ) { throw new AssertionFailure( "possible non-threadsafe access to session" ); } - entry.postInsert( getState() ); - - if ( persister.hasInsertGeneratedProperties() ) { - persister.processInsertGeneratedProperties( id, instance, getState(), session ); - if ( persister.isVersionPropertyGenerated() ) { - version = Versioning.getVersion( getState(), persister ); - } - entry.postUpdate( instance, getState(), version ); - } - + handleGeneratedProperties( entry ); persistenceContext.registerInsertedKey( persister, getId() ); addCollectionsByKeyToPersistenceContext( persistenceContext, getState() ); } - - final SessionFactoryImplementor factory = session.getFactory(); - - final StatisticsImplementor statistics = factory.getStatistics(); - if ( isCachePutEnabled( persister, session ) ) { - final CacheEntry ce = persister.buildCacheEntry( - instance, - getState(), - version, - session - ); - cacheEntry = persister.getCacheEntryStructure().structure( ce ); - final EntityDataAccess cache = persister.getCacheAccessStrategy(); - final Object ck = cache.generateCacheKey( id, persister, factory, session.getTenantIdentifier() ); - - final boolean put = cacheInsert( persister, ck ); - - if ( put && statistics.isStatisticsEnabled() ) { - statistics.entityCachePut( - StatsHelper.INSTANCE.getRootEntityRole( persister ), - cache.getRegion().getName() - ); - } - } - + putCacheIfNecessary(); handleNaturalIdPostSaveNotifications( id ); - postInsert(); + final StatisticsImplementor statistics = session.getFactory().getStatistics(); if ( statistics.isStatisticsEnabled() && !veto ) { statistics.insertEntity( getPersister().getEntityName() ); } @@ -156,11 +121,44 @@ public class EntityInsertAction extends AbstractEntityInsertAction { markExecuted(); } + private void handleGeneratedProperties(EntityEntry entry) { + final EntityPersister persister = getPersister(); + if ( persister.hasInsertGeneratedProperties() ) { + final Object instance = getInstance(); + persister.processInsertGeneratedProperties( getId(), instance, getState(), getSession() ); + if ( persister.isVersionPropertyGenerated() ) { + version = Versioning.getVersion( getState(), persister); + } + entry.postUpdate( instance, getState(), version ); + } + } + + private void putCacheIfNecessary() { + final EntityPersister persister = getPersister(); + final SharedSessionContractImplementor session = getSession(); + if ( isCachePutEnabled( persister, session ) ) { + final SessionFactoryImplementor factory = session.getFactory(); + final CacheEntry ce = persister.buildCacheEntry( getInstance(), getState(), version, session ); + cacheEntry = persister.getCacheEntryStructure().structure( ce ); + final EntityDataAccess cache = persister.getCacheAccessStrategy(); + final Object ck = cache.generateCacheKey( getId(), persister, factory, session.getTenantIdentifier() ); + final boolean put = cacheInsert( persister, ck ); + + final StatisticsImplementor statistics = factory.getStatistics(); + if ( put && statistics.isStatisticsEnabled() ) { + statistics.entityCachePut( + StatsHelper.INSTANCE.getRootEntityRole( persister ), + cache.getRegion().getName() + ); + } + } + } + protected boolean cacheInsert(EntityPersister persister, Object ck) { SharedSessionContractImplementor session = getSession(); try { session.getEventListenerManager().cachePutStart(); - return persister.getCacheAccessStrategy().insert( session, ck, cacheEntry, version); + return persister.getCacheAccessStrategy().insert( session, ck, cacheEntry, version ); } finally { session.getEventListenerManager().cachePutEnd(); @@ -184,9 +182,9 @@ public class EntityInsertAction extends AbstractEntityInsertAction { } protected void postCommitInsert(boolean success) { - getFastSessionServices() - .eventListenerGroup_POST_COMMIT_INSERT - .fireLazyEventOnEachListener( this::newPostInsertEvent, success ? PostInsertEventListener::onPostInsert : this::postCommitOnFailure ); + getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT + .fireLazyEventOnEachListener( this::newPostInsertEvent, + success ? PostInsertEventListener::onPostInsert : this::postCommitOnFailure ); } private void postCommitOnFailure(PostInsertEventListener listener, PostInsertEvent event) { @@ -202,7 +200,8 @@ public class EntityInsertAction extends AbstractEntityInsertAction { protected boolean preInsert() { boolean veto = false; - final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_INSERT; + final EventListenerGroup listenerGroup + = getFastSessionServices().eventListenerGroup_PRE_INSERT; if ( listenerGroup.isEmpty() ) { return veto; } @@ -247,7 +246,8 @@ public class EntityInsertAction extends AbstractEntityInsertAction { @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT; + final EventListenerGroup group + = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT; for ( PostInsertEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; @@ -258,8 +258,8 @@ public class EntityInsertAction extends AbstractEntityInsertAction { protected boolean isCachePutEnabled(EntityPersister persister, SharedSessionContractImplementor session) { return persister.canWriteToCache() - && !persister.isCacheInvalidationRequired() - && session.getCacheMode().isPutEnabled(); + && !persister.isCacheInvalidationRequired() + && session.getCacheMode().isPutEnabled(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index 33b2d5c663..01f0efe042 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -15,7 +15,6 @@ import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.engine.internal.Versioning; import org.hibernate.engine.spi.CachedNaturalIdValueSource; import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionEventListenerManager; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -37,6 +36,7 @@ import org.hibernate.type.TypeHelper; * The action for performing entity updates. */ public class EntityUpdateAction extends EntityAction { + private final Object[] state; private final Object[] previousState; private final Object previousVersion; @@ -91,7 +91,7 @@ public class EntityUpdateAction extends EntityAction { previousNaturalIdValues = null; } else { - this.previousNaturalIdValues = determinePreviousNaturalIdValues( persister, naturalIdMapping, id, previousState, session ); + previousNaturalIdValues = determinePreviousNaturalIdValues( persister, naturalIdMapping, id, previousState, session ); session.getPersistenceContextInternal().getNaturalIdResolutions().manageLocalResolution( id, naturalIdMapping.extractNaturalIdFromEntityState( state, session ), @@ -107,12 +107,9 @@ public class EntityUpdateAction extends EntityAction { Object id, Object[] previousState, SharedSessionContractImplementor session) { - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - if ( previousState != null ) { - return naturalIdMapping.extractNaturalIdFromEntityState( previousState, session ); - } - - return persistenceContext.getNaturalIdSnapshot( id, persister ); + return previousState == null + ? session.getPersistenceContextInternal().getNaturalIdSnapshot( id, persister ) + : naturalIdMapping.extractNaturalIdFromEntityState( previousState, session ); } public Object[] getState() { @@ -129,56 +126,73 @@ public class EntityUpdateAction extends EntityAction { @Override public void execute() throws HibernateException { - final Object id = getId(); + if ( !preUpdate() ) { + final EntityPersister persister = getPersister(); + final SharedSessionContractImplementor session = getSession(); + final Object id = getId(); + final Object instance = getInstance(); + final Object previousVersion = getPreviousVersion(); + final Object ck = lockCacheItem( previousVersion ); + persister.update( id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, rowId, session ); + final EntityEntry entry = session.getPersistenceContextInternal().getEntry( instance ); + if ( entry == null ) { + throw new AssertionFailure( "possible non thread safe access to session" ); + } + handleGeneratedProperties( entry ); + updateCacheItem( previousVersion, ck, entry ); + handleNaturalIdResolutions( persister, session, id ); + postUpdate(); + + final StatisticsImplementor statistics = session.getFactory().getStatistics(); + if ( statistics.isStatisticsEnabled() ) { + statistics.updateEntity( getPersister().getEntityName() ); + } + } + } + + private void handleNaturalIdResolutions(EntityPersister persister, SharedSessionContractImplementor session, Object id) { + if ( naturalIdMapping != null ) { + session.getPersistenceContextInternal().getNaturalIdResolutions().manageSharedResolution( + id, + naturalIdMapping.extractNaturalIdFromEntityState( state, session), + previousNaturalIdValues, + persister, + CachedNaturalIdValueSource.UPDATE + ); + } + } + + private void updateCacheItem(Object previousVersion, Object ck, EntityEntry entry) { + final EntityPersister persister = getPersister(); + if ( persister.canWriteToCache() ) { + final SharedSessionContractImplementor session = getSession(); + if ( persister.isCacheInvalidationRequired() || entry.getStatus() != Status.MANAGED ) { + persister.getCacheAccessStrategy().remove( session, ck ); + } + else if ( session.getCacheMode().isPutEnabled() ) { + //TODO: inefficient if that cache is just going to ignore the updated state! + final CacheEntry ce = persister.buildCacheEntry( getInstance(), state, nextVersion, getSession() ); + cacheEntry = persister.getCacheEntryStructure().structure( ce ); + final boolean put = updateCache( persister, previousVersion, ck ); + + final StatisticsImplementor statistics = session.getFactory().getStatistics(); + if ( put && statistics.isStatisticsEnabled() ) { + statistics.entityCachePut( + StatsHelper.INSTANCE.getRootEntityRole( persister ), + getPersister().getCacheAccessStrategy().getRegion().getName() + ); + } + } + } + } + + private void handleGeneratedProperties(EntityEntry entry) { final EntityPersister persister = getPersister(); - final SharedSessionContractImplementor session = getSession(); final Object instance = getInstance(); - if ( preUpdate() ) { - return; - } - - final SessionFactoryImplementor factory = session.getFactory(); - Object previousVersion = this.previousVersion; - if ( persister.isVersionPropertyGenerated() ) { - // we need to grab the version value from the entity, otherwise - // we have issues with generated-version entities that may have - // multiple actions queued during the same flush - previousVersion = persister.getVersion( instance ); - } - - final Object ck; - if ( persister.canWriteToCache() ) { - final EntityDataAccess cache = persister.getCacheAccessStrategy(); - ck = cache.generateCacheKey( - id, - persister, - factory, - session.getTenantIdentifier() - ); - lock = cache.lockItem( session, ck, previousVersion ); - } - else { - ck = null; - } - persister.update( - id, - state, - dirtyFields, - hasDirtyCollection, - previousState, - previousVersion, - instance, - rowId, - session - ); - - final EntityEntry entry = session.getPersistenceContextInternal().getEntry( instance ); - if ( entry == null ) { - throw new AssertionFailure( "possible non thread safe access to session" ); - } - if ( entry.getStatus() == Status.MANAGED || persister.isVersionPropertyGenerated() ) { + final SharedSessionContractImplementor session = getSession(); + final Object id = getId(); // get the updated snapshot of the entity state by cloning current state; // it is safe to copy in place, since by this time no-one else (should have) // has a reference to the array @@ -194,7 +208,7 @@ public class EntityUpdateAction extends EntityAction { // values... persister.processUpdateGeneratedProperties( id, instance, state, session ); if ( persister.isVersionPropertyGenerated() ) { - nextVersion = Versioning.getVersion( state, persister ); + nextVersion = Versioning.getVersion( state, persister); } } // have the entity entry doAfterTransactionCompletion post-update processing, passing it the @@ -207,52 +221,47 @@ public class EntityUpdateAction extends EntityAction { final boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned() && entityMetamodel.getOptimisticLockStyle().isAllOrDirty(); if ( isImpliedOptimisticLocking && entry.getLoadedState() != null ) { - // The entity will be deleted and because we are going to create a delete statement that uses - // all the state values in the where clause, the entry state needs to be updated otherwise the statement execution will - // not delete any row (see HHH-15218). + // The entity will be deleted and because we are going to create a delete statement + // that uses all the state values in the where clause, the entry state needs to be + // updated otherwise the statement execution will not delete any row (see HHH-15218). entry.postUpdate( instance, state, nextVersion ); } } - - final StatisticsImplementor statistics = factory.getStatistics(); - if ( persister.canWriteToCache() ) { - if ( persister.isCacheInvalidationRequired() || entry.getStatus() != Status.MANAGED ) { - persister.getCacheAccessStrategy().remove( session, ck ); - } - else if ( session.getCacheMode().isPutEnabled() ) { - //TODO: inefficient if that cache is just going to ignore the updated state! - final CacheEntry ce = persister.buildCacheEntry( instance, state, nextVersion, getSession() ); - cacheEntry = persister.getCacheEntryStructure().structure( ce ); - - final boolean put = cacheUpdate( persister, previousVersion, ck ); - if ( put && statistics.isStatisticsEnabled() ) { - statistics.entityCachePut( - StatsHelper.INSTANCE.getRootEntityRole( persister ), - getPersister().getCacheAccessStrategy().getRegion().getName() - ); - } - } - } - - if ( naturalIdMapping != null ) { - session.getPersistenceContextInternal().getNaturalIdResolutions().manageSharedResolution( - id, - naturalIdMapping.extractNaturalIdFromEntityState( state, session ), - previousNaturalIdValues, - persister, - CachedNaturalIdValueSource.UPDATE - ); - } - - postUpdate(); - - if ( statistics.isStatisticsEnabled() ) { - statistics.updateEntity( getPersister().getEntityName() ); - } - } - protected boolean cacheUpdate(EntityPersister persister, Object previousVersion, Object ck) { + private Object getPreviousVersion() { + final EntityPersister persister = getPersister(); + if ( persister.isVersionPropertyGenerated() ) { + // we need to grab the version value from the entity, otherwise + // we have issues with generated-version entities that may have + // multiple actions queued during the same flush + return persister.getVersion( getInstance() ); + } + else { + return previousVersion; + } + } + + private Object lockCacheItem(Object previousVersion) { + final EntityPersister persister = getPersister(); + if ( persister.canWriteToCache() ) { + final SharedSessionContractImplementor session = getSession(); + final EntityDataAccess cache = persister.getCacheAccessStrategy(); + final Object ck = cache.generateCacheKey( + getId(), + persister, + session.getFactory(), + session.getTenantIdentifier() + ); + lock = cache.lockItem( session, ck, previousVersion ); + return ck; + } + else { + return null; + } + } + + protected boolean updateCache(EntityPersister persister, Object previousVersion, Object ck) { final SharedSessionContractImplementor session = getSession(); try { session.getEventListenerManager().cachePutStart(); @@ -264,28 +273,30 @@ public class EntityUpdateAction extends EntityAction { } protected boolean preUpdate() { - boolean veto = false; - final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_UPDATE; + final EventListenerGroup listenerGroup + = getFastSessionServices().eventListenerGroup_PRE_UPDATE; if ( listenerGroup.isEmpty() ) { + return false; + } + else { + final PreUpdateEvent event = new PreUpdateEvent( + getInstance(), + getId(), + state, + previousState, + getPersister(), + eventSource() + ); + boolean veto = false; + for ( PreUpdateEventListener listener : listenerGroup.listeners() ) { + veto |= listener.onPreUpdate( event ); + } return veto; } - final PreUpdateEvent event = new PreUpdateEvent( - getInstance(), - getId(), - state, - previousState, - getPersister(), - eventSource() - ); - for ( PreUpdateEventListener listener : listenerGroup.listeners() ) { - veto |= listener.onPreUpdate( event ); - } - return veto; } protected void postUpdate() { - getFastSessionServices() - .eventListenerGroup_POST_UPDATE + getFastSessionServices().eventListenerGroup_POST_UPDATE .fireLazyEventOnEachListener( this::newPostUpdateEvent, PostUpdateEventListener::onPostUpdate ); } @@ -302,9 +313,9 @@ public class EntityUpdateAction extends EntityAction { } protected void postCommitUpdate(boolean success) { - getFastSessionServices() - .eventListenerGroup_POST_COMMIT_UPDATE - .fireLazyEventOnEachListener( this::newPostUpdateEvent, success ? PostUpdateEventListener::onPostUpdate : this::onPostCommitFailure ); + getFastSessionServices().eventListenerGroup_POST_COMMIT_UPDATE + .fireLazyEventOnEachListener( this::newPostUpdateEvent, + success ? PostUpdateEventListener::onPostUpdate : this::onPostCommitFailure ); } private void onPostCommitFailure(PostUpdateEventListener listener, PostUpdateEvent event) { @@ -319,18 +330,23 @@ public class EntityUpdateAction extends EntityAction { @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_UPDATE; + final EventListenerGroup group + = getFastSessionServices().eventListenerGroup_POST_COMMIT_UPDATE; for ( PostUpdateEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; } } - return false; } @Override public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws CacheException { + updateCacheIfNecessary( success, session ); + postCommitUpdate( success ); + } + + private void updateCacheIfNecessary(boolean success, SharedSessionContractImplementor session) { final EntityPersister persister = getPersister(); if ( persister.canWriteToCache() ) { final EntityDataAccess cache = persister.getCacheAccessStrategy(); @@ -342,38 +358,40 @@ public class EntityUpdateAction extends EntityAction { session.getTenantIdentifier() ); - - if ( success && - cacheEntry != null && - !persister.isCacheInvalidationRequired() && - session.getCacheMode().isPutEnabled() ) { - final boolean put = cacheAfterUpdate( cache, ck ); - - final StatisticsImplementor statistics = factory.getStatistics(); - if ( put && statistics.isStatisticsEnabled() ) { - statistics.entityCachePut( - StatsHelper.INSTANCE.getRootEntityRole( persister ), - cache.getRegion().getName() - ); - } + if ( cacheUpdateRequired( success, persister, session ) ) { + cacheAfterUpdate( cache, ck, session); } else { cache.unlockItem( session, ck, lock ); } } - postCommitUpdate( success ); } - protected boolean cacheAfterUpdate(EntityDataAccess cache, Object ck) { - final SharedSessionContractImplementor session = getSession(); - SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); + private boolean cacheUpdateRequired(boolean success, EntityPersister persister, SharedSessionContractImplementor session) { + return success + && cacheEntry != null + && !persister.isCacheInvalidationRequired() + && session.getCacheMode().isPutEnabled(); + } + + protected void cacheAfterUpdate(EntityDataAccess cache, Object ck, SharedSessionContractImplementor session) { + final SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); try { eventListenerManager.cachePutStart(); - return cache.afterUpdate( session, ck, cacheEntry, nextVersion, previousVersion, lock ); + boolean put = cache.afterUpdate( session, ck, cacheEntry, nextVersion, previousVersion, lock ); + + final StatisticsImplementor statistics = session.getFactory().getStatistics(); + if ( put && statistics.isStatisticsEnabled() ) { + statistics.entityCachePut( + StatsHelper.INSTANCE.getRootEntityRole( getPersister() ), + cache.getRegion().getName() + ); + } } finally { eventListenerManager.cachePutEnd(); } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java index 7381a69196..edaa8dcf13 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java @@ -20,6 +20,7 @@ import org.hibernate.pretty.MessageHelper; * @author Scott Marlow */ public class EntityVerifyVersionProcess implements BeforeTransactionCompletionProcess { + private final Object object; /** @@ -35,19 +36,18 @@ public class EntityVerifyVersionProcess implements BeforeTransactionCompletionPr public void doBeforeTransactionCompletion(SessionImplementor session) { final EntityEntry entry = session.getPersistenceContext().getEntry( object ); // Don't check version for an entity that is not in the PersistenceContext; - if ( entry == null ) { - return; - } - - final EntityPersister persister = entry.getPersister(); - final Object latestVersion = persister.getCurrentVersion( entry.getId(), session ); - if ( !entry.getVersion().equals( latestVersion ) ) { - throw new OptimisticEntityLockException( - object, - "Newer version [" + latestVersion + - "] of entity [" + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) + - "] found in database" - ); + if ( entry != null ) { + final Object latestVersion = entry.getPersister().getCurrentVersion( entry.getId(), session ); + if ( !entry.getVersion().equals( latestVersion ) ) { + throw new OptimisticEntityLockException( + object, + "Newer version [" + + latestVersion + + "] of entity [" + + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) + + "] found in database" + ); + } } } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java b/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java index 0ebc2d1e47..509e554192 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/UnresolvedEntityInsertActions.java @@ -160,7 +160,6 @@ public class UnresolvedEntityInsertActions { return dependenciesByAction.isEmpty(); } - @SuppressWarnings("unchecked") private void addDependenciesByTransientEntity(AbstractEntityInsertAction insert, NonNullableTransientDependencies dependencies) { for ( Object transientEntity : dependencies.getNonNullableTransientEntities() ) { Set dependentActions = dependentActionsByTransientEntity.get( transientEntity ); @@ -182,7 +181,6 @@ public class UnresolvedEntityInsertActions { * * @throws IllegalArgumentException if {@code managedEntity} did not have managed or read-only status. */ - @SuppressWarnings("unchecked") public Set resolveDependentActions(Object managedEntity, SessionImplementor session) { final EntityEntry entityEntry = session.getPersistenceContextInternal().getEntry( managedEntity ); if ( entityEntry.getStatus() != Status.MANAGED && entityEntry.getStatus() != Status.READ_ONLY ) {