minor code cleanups to Actions
This commit is contained in:
parent
a11ebdeefc
commit
8f9b998894
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ) ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PreDeleteEventListener> listenerGroup = getFastSessionServices().eventListenerGroup_PRE_DELETE;
|
||||
final EventListenerGroup<PreDeleteEventListener> 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<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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,17 +172,20 @@ 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;
|
||||
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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<PreUpdateEventListener> listenerGroup = getFastSessionServices().eventListenerGroup_PRE_UPDATE;
|
||||
final EventListenerGroup<PreUpdateEventListener> 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<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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
Loading…
Reference in New Issue