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.results.graph.DomainResult;
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
@ -180,7 +181,7 @@ public class SubselectFetch {
}
private boolean shouldAddSubselectFetch(LoadingEntityEntry entry) {
if ( entry.getEntityInitializer().isEntityResultInitializer() ) {
if ( entry.getEntityInitializer() instanceof EntityResultInitializer ) {
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.
*/
public abstract class AbstractImmediateCollectionInitializer extends AbstractCollectionInitializer {
private final LockMode lockMode;
// per-row state
private LoadingCollectionEntryImpl responsibility;
@ -61,7 +60,6 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
DomainResultAssembler<?> collectionValueKeyResultAssembler) {
super( collectionPath, collectionAttributeMapping, parentAccess, collectionKeyResultAssembler );
this.collectionValueKeyResultAssembler = collectionValueKeyResultAssembler;
this.lockMode = lockMode;
}
protected abstract String getSimpleConcreteImplName();

View File

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

View File

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

View File

@ -42,6 +42,7 @@ import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.proxy.map.MapProxy;
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.Fetch;
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.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
@ -409,7 +411,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
final Object entityInstanceFromExecutionContext =
rowProcessingState.getJdbcValuesSourceProcessingState().getExecutionContext().getEntityInstance();
if ( isProxyInstance( proxy ) ) {
if ( isEntityResultInitializer() && entityInstanceFromExecutionContext != null ) {
if ( this instanceof EntityResultInitializer && entityInstanceFromExecutionContext != null ) {
entityInstance = entityInstanceFromExecutionContext;
registerLoadingEntity( rowProcessingState, entityInstance );
}
@ -421,8 +423,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
final Object existingEntity = persistenceContext.getEntity( entityKey );
if ( existingEntity != null ) {
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;
registerLoadingEntity( rowProcessingState, entityInstance );
}
@ -457,6 +463,26 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
&& ( 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
* 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
public EntityPersister getConcreteDescriptor() {
return concreteDescriptor;

View File

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

View File

@ -83,6 +83,11 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
return;
}
final EntityInitializer parentEntityInitializer = getParentEntityInitializer( parentAccess );
if ( parentEntityInitializer != null && parentEntityInitializer.isInitialized() ) {
return;
}
if ( !isAttributeAssignableToConcreteDescriptor( parentAccess, referencedModelPart ) ) {
return;
}
@ -115,7 +120,7 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
if ( referencedModelPart.isOptional()
&& parentAccess != null
&& !parentAccess.isEmbeddableInitializer()
&& isEnhancedForLazyLoading( parentAccess ) ) {
&& isEnhancedForLazyLoading( parentEntityInitializer ) ) {
entityInstance = LazyPropertyInitializer.UNFETCHED_PROPERTY;
}
else {
@ -141,7 +146,7 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
if ( entityInstance == null ) {
if ( parentAccess != null
&& !parentAccess.isEmbeddableInitializer()
&& isEnhancedForLazyLoading( parentAccess ) ) {
&& isEnhancedForLazyLoading( parentEntityInitializer ) ) {
return;
}
entityInstance = ( (UniqueKeyLoadable) concreteDescriptor ).loadByUniqueKey(
@ -180,8 +185,16 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
}
}
private static boolean isEnhancedForLazyLoading(FetchParentAccess parentAccess) {
return parentAccess.findFirstEntityInitializer().getEntityDescriptor().getBytecodeEnhancementMetadata()
private EntityInitializer getParentEntityInitializer(FetchParentAccess parentAccess) {
if ( parentAccess != null ) {
return parentAccess.findFirstEntityInitializer();
}
return null;
}
private static boolean isEnhancedForLazyLoading(EntityInitializer parentEntityIntialiazer) {
return parentEntityIntialiazer != null && parentEntityIntialiazer.getEntityDescriptor()
.getBytecodeEnhancementMetadata()
.isEnhancedForLazyLoading();
}
@ -238,4 +251,9 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
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() + ")";
}
@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.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource;