minor code cleanups to Actions

This commit is contained in:
Gavin King 2022-09-29 23:20:15 +02:00
parent a11ebdeefc
commit 8f9b998894
13 changed files with 361 additions and 349 deletions

View File

@ -210,12 +210,8 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
*/
public void handleNaturalIdPostSaveNotifications(Object generatedId) {
final NaturalIdMapping naturalIdMapping = getPersister().getNaturalIdMapping();
if ( naturalIdMapping == null ) {
return;
}
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(
@ -235,3 +231,4 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
);
}
}
}

View File

@ -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<EntityCleanup> 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<String> 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<String> 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 <strong>table names</strong>. 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 <strong>table names</strong>. 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<String> tableSpaces) {
final LinkedHashSet<String> 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 ) ) {

View File

@ -28,6 +28,7 @@ import org.hibernate.pretty.MessageHelper;
* @author Gavin King
*/
public abstract class CollectionAction implements Executable, Serializable, Comparable<CollectionAction> {
private transient CollectionPersister persister;
private transient SharedSessionContractImplementor session;
private final PersistentCollection<?> collection;

View File

@ -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() {

View File

@ -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() {

View File

@ -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() {

View File

@ -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 {
return roleComparison != 0 ? roleComparison
//then by id
return persister.getIdentifierType().compare( id, action.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 ) );
}
}

View File

@ -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,16 +186,16 @@ 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<PreDeleteEventListener> listenerGroup = getFastSessionServices().eventListenerGroup_PRE_DELETE;
final EventListenerGroup<PreDeleteEventListener> listenerGroup
= getFastSessionServices().eventListenerGroup_PRE_DELETE;
if ( listenerGroup.isEmpty() ) {
return false;
}
else {
final PreDeleteEvent event = new PreDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() );
boolean veto = false;
for ( PreDeleteEventListener listener : listenerGroup.listeners() ) {
@ -220,10 +203,10 @@ public class EntityDeleteAction extends EntityAction {
}
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<PostDeleteEventListener> eventListeners = getFastSessionServices()
.eventListenerGroup_POST_COMMIT_DELETE;
final EventListenerGroup<PostDeleteEventListener> 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<PostDeleteEventListener> 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 );
}
}
}

View File

@ -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<PostInsertEventListener> group = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT;
final EventListenerGroup<PostInsertEventListener> 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,18 +172,21 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction {
}
protected boolean preInsert() {
final EventListenerGroup<PreInsertEventListener> listenerGroup = getFastSessionServices().eventListenerGroup_PRE_INSERT;
final EventListenerGroup<PreInsertEventListener> listenerGroup
= getFastSessionServices().eventListenerGroup_PRE_INSERT;
if ( listenerGroup.isEmpty() ) {
// NO_VETO
return false;
}
boolean veto = false;
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;
}
}
/**
* Access to the generated identifier
@ -218,9 +220,11 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction {
}
protected EntityKey generateDelayedEntityKey() {
if ( !isDelayed ) {
throw new AssertionFailure( "cannot request delayed entity-key for early-insert post-insert-id generation" );
}
if ( isDelayed ) {
return getSession().generateEntityKey( getDelayedId(), getPersister() );
}
else {
throw new AssertionFailure( "cannot request delayed entity-key for early-insert post-insert-id generation" );
}
}
}

View File

@ -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,55 +89,62 @@ 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() );
handleGeneratedProperties( entry );
persistenceContext.registerInsertedKey( persister, getId() );
addCollectionsByKeyToPersistenceContext( persistenceContext, getState() );
}
putCacheIfNecessary();
handleNaturalIdPostSaveNotifications( id );
postInsert();
final StatisticsImplementor statistics = session.getFactory().getStatistics();
if ( statistics.isStatisticsEnabled() && !veto ) {
statistics.insertEntity( getPersister().getEntityName() );
}
markExecuted();
}
private void handleGeneratedProperties(EntityEntry entry) {
final EntityPersister persister = getPersister();
if ( persister.hasInsertGeneratedProperties() ) {
persister.processInsertGeneratedProperties( id, instance, getState(), session );
final Object instance = getInstance();
persister.processInsertGeneratedProperties( getId(), instance, getState(), getSession() );
if ( persister.isVersionPropertyGenerated() ) {
version = Versioning.getVersion( getState(), persister);
}
entry.postUpdate( instance, getState(), version );
}
persistenceContext.registerInsertedKey( persister, getId() );
addCollectionsByKeyToPersistenceContext( persistenceContext, getState() );
}
final SessionFactoryImplementor factory = session.getFactory();
final StatisticsImplementor statistics = factory.getStatistics();
private void putCacheIfNecessary() {
final EntityPersister persister = getPersister();
final SharedSessionContractImplementor session = getSession();
if ( isCachePutEnabled( persister, session ) ) {
final CacheEntry ce = persister.buildCacheEntry(
instance,
getState(),
version,
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( id, persister, factory, session.getTenantIdentifier() );
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 ),
@ -144,16 +152,6 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
);
}
}
handleNaturalIdPostSaveNotifications( id );
postInsert();
if ( statistics.isStatisticsEnabled() && !veto ) {
statistics.insertEntity( getPersister().getEntityName() );
}
markExecuted();
}
protected boolean cacheInsert(EntityPersister persister, Object ck) {
@ -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<PreInsertEventListener> listenerGroup = getFastSessionServices().eventListenerGroup_PRE_INSERT;
final EventListenerGroup<PreInsertEventListener> 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<PostInsertEventListener> group = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT;
final EventListenerGroup<PostInsertEventListener> group
= getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT;
for ( PostInsertEventListener listener : group.listeners() ) {
if ( listener.requiresPostCommitHandling( getPersister() ) ) {
return true;

View File

@ -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();
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 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 Object instance = getInstance();
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
@ -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();
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() ) {
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,
final SharedSessionContractImplementor session = getSession();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
getId(),
persister,
CachedNaturalIdValueSource.UPDATE
session.getFactory(),
session.getTenantIdentifier()
);
lock = cache.lockItem( session, ck, previousVersion );
return ck;
}
else {
return null;
}
}
postUpdate();
if ( statistics.isStatisticsEnabled() ) {
statistics.updateEntity( getPersister().getEntityName() );
}
}
protected boolean cacheUpdate(EntityPersister persister, Object previousVersion, Object ck) {
protected boolean updateCache(EntityPersister persister, Object previousVersion, Object ck) {
final SharedSessionContractImplementor session = getSession();
try {
session.getEventListenerManager().cachePutStart();
@ -264,11 +273,12 @@ public class EntityUpdateAction extends EntityAction {
}
protected boolean preUpdate() {
boolean veto = false;
final EventListenerGroup<PreUpdateEventListener> listenerGroup = getFastSessionServices().eventListenerGroup_PRE_UPDATE;
final EventListenerGroup<PreUpdateEventListener> listenerGroup
= getFastSessionServices().eventListenerGroup_PRE_UPDATE;
if ( listenerGroup.isEmpty() ) {
return veto;
return false;
}
else {
final PreUpdateEvent event = new PreUpdateEvent(
getInstance(),
getId(),
@ -277,15 +287,16 @@ public class EntityUpdateAction extends EntityAction {
getPersister(),
eventSource()
);
boolean veto = false;
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<PostUpdateEventListener> group = getFastSessionServices().eventListenerGroup_POST_COMMIT_UPDATE;
final EventListenerGroup<PostUpdateEventListener> 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();
}
}
}

View File

@ -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 != 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"
"Newer version ["
+ latestVersion
+ "] of entity ["
+ MessageHelper.infoString( entry.getEntityName(), entry.getId() )
+ "] found in database"
);
}
}
}
}

View File

@ -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<AbstractEntityInsertAction> 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<AbstractEntityInsertAction> resolveDependentActions(Object managedEntity, SessionImplementor session) {
final EntityEntry entityEntry = session.getPersistenceContextInternal().getEntry( managedEntity );
if ( entityEntry.getStatus() != Status.MANAGED && entityEntry.getStatus() != Status.READ_ONLY ) {