HHH-15854 Improve CollectionInitializer and EntityDelayedFetchInitializer resolveInstance methods performance when the parent entity is initialized

This commit is contained in:
Andrea Boriero 2022-12-11 15:01:41 +01:00 committed by Andrea Boriero
parent 312d7e11a6
commit 98957c3509
9 changed files with 77 additions and 15 deletions

View File

@ -21,6 +21,7 @@ import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry; import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
/** /**
* Encapsulates details related to entities which contain sub-select-fetchable * Encapsulates details related to entities which contain sub-select-fetchable
@ -180,7 +181,7 @@ public class SubselectFetch {
} }
private boolean shouldAddSubselectFetch(LoadingEntityEntry entry) { private boolean shouldAddSubselectFetch(LoadingEntityEntry entry) {
if ( entry.getEntityInitializer().isEntityResultInitializer() ) { if ( entry.getEntityInitializer() instanceof EntityResultInitializer ) {
return true; return true;
} }

View File

@ -36,7 +36,6 @@ import static org.hibernate.sql.results.graph.collection.CollectionLoadingLogger
* @implNote Mainly an intention contract wrt the immediacy of the fetch. * @implNote Mainly an intention contract wrt the immediacy of the fetch.
*/ */
public abstract class AbstractImmediateCollectionInitializer extends AbstractCollectionInitializer { public abstract class AbstractImmediateCollectionInitializer extends AbstractCollectionInitializer {
private final LockMode lockMode;
// per-row state // per-row state
private LoadingCollectionEntryImpl responsibility; private LoadingCollectionEntryImpl responsibility;
@ -61,7 +60,6 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
DomainResultAssembler<?> collectionValueKeyResultAssembler) { DomainResultAssembler<?> collectionValueKeyResultAssembler) {
super( collectionPath, collectionAttributeMapping, parentAccess, collectionKeyResultAssembler ); super( collectionPath, collectionAttributeMapping, parentAccess, collectionKeyResultAssembler );
this.collectionValueKeyResultAssembler = collectionValueKeyResultAssembler; this.collectionValueKeyResultAssembler = collectionValueKeyResultAssembler;
this.lockMode = lockMode;
} }
protected abstract String getSimpleConcreteImplName(); protected abstract String getSimpleConcreteImplName();

View File

@ -11,6 +11,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
/** /**
@ -29,6 +30,12 @@ public class DelayedCollectionInitializer extends AbstractCollectionInitializer
@Override @Override
public void resolveInstance(RowProcessingState rowProcessingState) { public void resolveInstance(RowProcessingState rowProcessingState) {
if ( parentAccess != null ) {
final EntityInitializer parentEntityInitializer = parentAccess.findFirstEntityInitializer();
if ( parentEntityInitializer != null && parentEntityInitializer.isInitialized() ) {
return;
}
}
resolveInstance( rowProcessingState, false ); resolveInstance( rowProcessingState, false );
} }

View File

@ -143,12 +143,19 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
@Override @Override
public FetchParentAccess findFirstEntityDescriptorAccess() { public FetchParentAccess findFirstEntityDescriptorAccess() {
return getFetchParentAccess().findFirstEntityDescriptorAccess(); if ( fetchParentAccess == null ) {
return null;
}
return fetchParentAccess.findFirstEntityDescriptorAccess();
} }
@Override @Override
public EntityInitializer findFirstEntityInitializer() { public EntityInitializer findFirstEntityInitializer() {
return findFirstEntityDescriptorAccess().findFirstEntityInitializer(); final FetchParentAccess firstEntityDescriptorAccess = findFirstEntityDescriptorAccess();
if ( firstEntityDescriptorAccess == null ) {
return null;
}
return firstEntityDescriptorAccess.findFirstEntityInitializer();
} }
@Override @Override

View File

@ -42,6 +42,7 @@ import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
import org.hibernate.proxy.map.MapProxy; import org.hibernate.proxy.map.MapProxy;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
@ -51,6 +52,7 @@ import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.basic.BasicResultAssembler; import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
import org.hibernate.sql.results.internal.NullValueAssembler; import org.hibernate.sql.results.internal.NullValueAssembler;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
@ -409,7 +411,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
final Object entityInstanceFromExecutionContext = final Object entityInstanceFromExecutionContext =
rowProcessingState.getJdbcValuesSourceProcessingState().getExecutionContext().getEntityInstance(); rowProcessingState.getJdbcValuesSourceProcessingState().getExecutionContext().getEntityInstance();
if ( isProxyInstance( proxy ) ) { if ( isProxyInstance( proxy ) ) {
if ( isEntityResultInitializer() && entityInstanceFromExecutionContext != null ) { if ( this instanceof EntityResultInitializer && entityInstanceFromExecutionContext != null ) {
entityInstance = entityInstanceFromExecutionContext; entityInstance = entityInstanceFromExecutionContext;
registerLoadingEntity( rowProcessingState, entityInstance ); registerLoadingEntity( rowProcessingState, entityInstance );
} }
@ -421,8 +423,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
final Object existingEntity = persistenceContext.getEntity( entityKey ); final Object existingEntity = persistenceContext.getEntity( entityKey );
if ( existingEntity != null ) { if ( existingEntity != null ) {
entityInstance = existingEntity; entityInstance = existingEntity;
if ( existingLoadingEntry == null && isExistingEntityInitialized( existingEntity ) ) {
notifyResolutionListeners( entityInstance );
this.isInitialized = true;
} }
else if ( isEntityResultInitializer() && entityInstanceFromExecutionContext != null ) { }
else if ( this instanceof EntityResultInitializer && entityInstanceFromExecutionContext != null ) {
entityInstance = entityInstanceFromExecutionContext; entityInstance = entityInstanceFromExecutionContext;
registerLoadingEntity( rowProcessingState, entityInstance ); registerLoadingEntity( rowProcessingState, entityInstance );
} }
@ -457,6 +463,26 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
&& ( proxy instanceof MapProxy || entityDescriptor.getJavaType().getJavaTypeClass().isInstance( proxy ) ); && ( proxy instanceof MapProxy || entityDescriptor.getJavaType().getJavaTypeClass().isInstance( proxy ) );
} }
private boolean isExistingEntityInitialized(Object existingEntity) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityInstance );
if ( lazyInitializer != null ) {
if ( lazyInitializer.isUninitialized() ) {
return false;
}
return true;
}
else if ( isPersistentAttributeInterceptable( existingEntity ) ) {
final PersistentAttributeInterceptor persistentAttributeInterceptor = asPersistentAttributeInterceptable(
entityInstance ).$$_hibernate_getInterceptor();
if ( persistentAttributeInterceptor == null || persistentAttributeInterceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
return false;
}
return true;
}
return true;
}
/** /**
* Check the version of the object in the {@code RowProcessingState} against * Check the version of the object in the {@code RowProcessingState} against
* the object version in the session cache, throwing an exception * the object version in the session cache, throwing an exception
@ -953,6 +979,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
} }
} }
@Override
public boolean isInitialized() {
return isInitialized;
}
@Override @Override
public EntityPersister getConcreteDescriptor() { public EntityPersister getConcreteDescriptor() {
return concreteDescriptor; return concreteDescriptor;

View File

@ -60,6 +60,9 @@ public interface EntityInitializer extends FetchParentAccess {
return this; return this;
} }
default boolean isInitialized() {
return false;
}
default boolean isEntityResultInitializer() { default boolean isEntityResultInitializer() {
return false; return false;

View File

@ -83,6 +83,11 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
return; return;
} }
final EntityInitializer parentEntityInitializer = getParentEntityInitializer( parentAccess );
if ( parentEntityInitializer != null && parentEntityInitializer.isInitialized() ) {
return;
}
if ( !isAttributeAssignableToConcreteDescriptor( parentAccess, referencedModelPart ) ) { if ( !isAttributeAssignableToConcreteDescriptor( parentAccess, referencedModelPart ) ) {
return; return;
} }
@ -115,7 +120,7 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
if ( referencedModelPart.isOptional() if ( referencedModelPart.isOptional()
&& parentAccess != null && parentAccess != null
&& !parentAccess.isEmbeddableInitializer() && !parentAccess.isEmbeddableInitializer()
&& isEnhancedForLazyLoading( parentAccess ) ) { && isEnhancedForLazyLoading( parentEntityInitializer ) ) {
entityInstance = LazyPropertyInitializer.UNFETCHED_PROPERTY; entityInstance = LazyPropertyInitializer.UNFETCHED_PROPERTY;
} }
else { else {
@ -141,7 +146,7 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
if ( entityInstance == null ) { if ( entityInstance == null ) {
if ( parentAccess != null if ( parentAccess != null
&& !parentAccess.isEmbeddableInitializer() && !parentAccess.isEmbeddableInitializer()
&& isEnhancedForLazyLoading( parentAccess ) ) { && isEnhancedForLazyLoading( parentEntityInitializer ) ) {
return; return;
} }
entityInstance = ( (UniqueKeyLoadable) concreteDescriptor ).loadByUniqueKey( entityInstance = ( (UniqueKeyLoadable) concreteDescriptor ).loadByUniqueKey(
@ -180,8 +185,16 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
} }
} }
private static boolean isEnhancedForLazyLoading(FetchParentAccess parentAccess) { private EntityInitializer getParentEntityInitializer(FetchParentAccess parentAccess) {
return parentAccess.findFirstEntityInitializer().getEntityDescriptor().getBytecodeEnhancementMetadata() if ( parentAccess != null ) {
return parentAccess.findFirstEntityInitializer();
}
return null;
}
private static boolean isEnhancedForLazyLoading(EntityInitializer parentEntityIntialiazer) {
return parentEntityIntialiazer != null && parentEntityIntialiazer.getEntityDescriptor()
.getBytecodeEnhancementMetadata()
.isEnhancedForLazyLoading(); .isEnhancedForLazyLoading();
} }
@ -238,4 +251,9 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
return "EntityDelayedFetchInitializer(" + LoggingHelper.toLoggableString( navigablePath ) + ")"; return "EntityDelayedFetchInitializer(" + LoggingHelper.toLoggableString( navigablePath ) + ")";
} }
@Override
public boolean isEntityResultInitializer() {
return true;
}
} }

View File

@ -57,8 +57,4 @@ public class EntityResultInitializer extends AbstractEntityInitializer {
return CONCRETE_NAME + "(" + getNavigablePath() + ")"; return CONCRETE_NAME + "(" + getNavigablePath() + ")";
} }
@Override
public boolean isEntityResultInitializer() {
return true;
}
} }

View File

@ -15,6 +15,7 @@ import java.util.function.BiConsumer;
import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey; import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;