From bbd8df93ca476e0669f08d95581b3e4d4abe8007 Mon Sep 17 00:00:00 2001 From: Gavin Date: Sun, 21 May 2023 18:37:49 +0200 Subject: [PATCH] HHH-16651 make persisters return adapted loaders for session batch size --- .../CollectionLoaderSubSelectFetch.java | 2 +- .../internal/EntityBatchLoaderArrayParam.java | 17 +- .../EntityBatchLoaderInPredicate.java | 8 +- .../MultiIdEntityLoaderArrayParam.java | 11 +- .../internal/MultiIdEntityLoaderStandard.java | 6 +- .../internal/StandardBatchLoaderFactory.java | 30 ++- .../hibernate/loader/ast/spi/Loadable.java | 14 +- .../internal/PluralAttributeMappingImpl.java | 5 + .../AbstractCollectionPersister.java | 191 +++++++++--------- .../entity/AbstractEntityPersister.java | 112 ++++++---- .../AnonymousTupleEntityValuedModelPart.java | 16 ++ 11 files changed, 222 insertions(+), 190 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CollectionLoaderSubSelectFetch.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CollectionLoaderSubSelectFetch.java index 969088273d..b983f95adb 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CollectionLoaderSubSelectFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CollectionLoaderSubSelectFetch.java @@ -46,7 +46,7 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader { public CollectionLoaderSubSelectFetch( PluralAttributeMapping attributeMapping, - DomainResult cachedDomainResult, + DomainResult cachedDomainResult, SubselectFetch subselect, SharedSessionContractImplementor session) { this.attributeMapping = attributeMapping; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderArrayParam.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderArrayParam.java index 36ff601a76..4bbcb1d584 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderArrayParam.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderArrayParam.java @@ -7,7 +7,6 @@ package org.hibernate.loader.ast.internal; import java.lang.reflect.Array; -import java.util.Collections; import java.util.Locale; import org.hibernate.LockOptions; @@ -16,7 +15,6 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.loader.ast.spi.EntityBatchLoader; import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader; import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; @@ -26,15 +24,9 @@ import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.query.spi.QueryOptions; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.select.SelectStatement; -import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl; -import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.internal.JdbcParameterImpl; import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcParameterBindings; -import org.hibernate.sql.results.internal.RowTransformerStandardImpl; -import org.hibernate.sql.results.spi.ListResultsConsumer; -import org.hibernate.type.BasicType; -import org.hibernate.type.BasicTypeRegistry; import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_DEBUG_ENABLED; import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER; @@ -162,13 +154,10 @@ public class EntityBatchLoaderArrayParam @Override public void prepare() { identifierMapping = (BasicEntityIdentifierMapping) getLoadable().getIdentifierMapping(); - final Class arrayClass = Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 ).getClass(); - - final BasicTypeRegistry basicTypeRegistry = sessionFactory.getTypeConfiguration().getBasicTypeRegistry(); - final BasicType arrayBasicType = basicTypeRegistry.getRegisteredType( arrayClass ); - + final Class arrayClass = + Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 ).getClass(); arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( - arrayBasicType, + sessionFactory.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ), identifierMapping.getJdbcMapping(), arrayClass, sessionFactory diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderInPredicate.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderInPredicate.java index 4b1ec52ded..15b0d193aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderInPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/EntityBatchLoaderInPredicate.java @@ -56,16 +56,18 @@ public class EntityBatchLoaderInPredicate /** * @param domainBatchSize The maximum number of entities we will initialize for each {@link #load load} - * @param sqlBatchSize The number of keys our SQL AST should be able to fetch */ public EntityBatchLoaderInPredicate( int domainBatchSize, - int sqlBatchSize, EntityMappingType entityDescriptor, SessionFactoryImplementor sessionFactory) { super( entityDescriptor, sessionFactory ); this.domainBatchSize = domainBatchSize; - this.sqlBatchSize = sqlBatchSize; + int idColumnCount = entityDescriptor.getEntityPersister().getIdentifierType().getColumnSpan( sessionFactory ); + this.sqlBatchSize = sessionFactory.getJdbcServices() + .getDialect() + .getBatchLoadSizingStrategy() + .determineOptimalBatchLoadSize( idColumnCount, domainBatchSize, false ); if ( MULTI_KEY_LOAD_DEBUG_ENABLED ) { MULTI_KEY_LOAD_LOGGER.debugf( diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderArrayParam.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderArrayParam.java index b623898862..28af2c4d30 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderArrayParam.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderArrayParam.java @@ -40,8 +40,6 @@ import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.results.internal.RowTransformerStandardImpl; import org.hibernate.sql.results.spi.ListResultsConsumer; -import org.hibernate.type.BasicType; -import org.hibernate.type.BasicTypeRegistry; import org.checkerframework.checker.nullness.qual.NonNull; @@ -385,7 +383,7 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade return ids; } - private X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) { + private X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) { //noinspection unchecked return (X[]) Array.newInstance( getIdentifierMapping().getJavaType().getJavaTypeClass(), length ); } @@ -393,14 +391,9 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade @Override public void prepare() { super.prepare(); - final Class arrayClass = createTypedArray( 0 ).getClass(); - - final BasicTypeRegistry basicTypeRegistry = getSessionFactory().getTypeConfiguration().getBasicTypeRegistry(); - final BasicType arrayBasicType = basicTypeRegistry.getRegisteredType( arrayClass ); - arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( - arrayBasicType, + getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ), getIdentifierMapping().getJdbcMapping(), arrayClass, getSessionFactory() diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderStandard.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderStandard.java index 95eb3bc2c2..6a594128ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiIdEntityLoaderStandard.java @@ -16,7 +16,6 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.PersistenceContext; @@ -28,7 +27,6 @@ import org.hibernate.event.spi.LoadEvent; import org.hibernate.event.spi.LoadEventListener; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; -import org.hibernate.mapping.PersistentClass; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.spi.QueryOptions; import org.hibernate.sql.ast.SqlAstTranslatorFactory; @@ -54,10 +52,10 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< public MultiIdEntityLoaderStandard( EntityPersister entityDescriptor, - PersistentClass bootDescriptor, + int idColumnSpan, SessionFactoryImplementor sessionFactory) { super( entityDescriptor, sessionFactory ); - this.idJdbcTypeCount = bootDescriptor.getIdentifier().getColumnSpan(); + this.idJdbcTypeCount = idColumnSpan; assert idJdbcTypeCount > 0; } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/StandardBatchLoaderFactory.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/StandardBatchLoaderFactory.java index a441fc22c7..2aa9685f74 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/StandardBatchLoaderFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/StandardBatchLoaderFactory.java @@ -18,9 +18,10 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.type.BasicType; -import org.hibernate.type.SqlTypes; import org.hibernate.type.Type; +import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.supportsSqlArrayType; + /** * Standard {@link BatchLoaderFactory} implementation * @@ -35,23 +36,18 @@ public class StandardBatchLoaderFactory implements BatchLoaderFactory { public EntityBatchLoader createEntityBatchLoader( int domainBatchSize, EntityMappingType entityDescriptor, SessionFactoryImplementor factory) { - final Dialect dialect = factory.getJdbcServices().getDialect(); // NOTE : don't use the EntityIdentifierMapping here because it will not be known until later final Type identifierType = entityDescriptor.getEntityPersister().getIdentifierType(); - final int idColumnCount = identifierType.getColumnSpan( factory ); - - if ( idColumnCount == 1 - && MultiKeyLoadHelper.supportsSqlArrayType( dialect ) + if ( identifierType.getColumnSpan( factory ) == 1 + && supportsSqlArrayType( factory.getJdbcServices().getDialect() ) && identifierType instanceof BasicType ) { // we can use a single ARRAY parameter to send all the ids return new EntityBatchLoaderArrayParam<>( domainBatchSize, entityDescriptor, factory ); } - - final int optimalBatchSize = dialect - .getBatchLoadSizingStrategy() - .determineOptimalBatchLoadSize( idColumnCount, domainBatchSize, false ); - return new EntityBatchLoaderInPredicate<>( domainBatchSize, optimalBatchSize, entityDescriptor, factory ); + else { + return new EntityBatchLoaderInPredicate<>( domainBatchSize, entityDescriptor, factory ); + } } @Override @@ -60,15 +56,13 @@ public class StandardBatchLoaderFactory implements BatchLoaderFactory { LoadQueryInfluencers influencers, PluralAttributeMapping attributeMapping, SessionFactoryImplementor factory) { - final Dialect dialect = factory.getJdbcServices().getDialect(); - final int columnCount = attributeMapping.getKeyDescriptor().getJdbcTypeCount(); - if ( columnCount == 1 - && dialect.supportsStandardArrays() - && dialect.getPreferredSqlTypeCodeForArray() == SqlTypes.ARRAY ) { + if ( attributeMapping.getKeyDescriptor().getJdbcTypeCount() == 1 + && supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ) { // we can use a single ARRAY parameter to send all the ids return new CollectionBatchLoaderArrayParam( domainBatchSize, influencers, attributeMapping, factory ); } - - return new CollectionBatchLoaderInPredicate( domainBatchSize, influencers, attributeMapping, factory ); + else { + return new CollectionBatchLoaderInPredicate( domainBatchSize, influencers, attributeMapping, factory ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java index fdff8e55c4..d048e963d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java @@ -30,17 +30,21 @@ public interface Loadable extends ModelPart, RootTableGroupProducer { default boolean isAffectedByInfluencers(LoadQueryInfluencers influencers) { return isAffectedByEntityGraph( influencers ) - || isAffectedByEnabledFetchProfiles( influencers ) - || isAffectedByEnabledFilters( influencers ); + || isAffectedByEnabledFetchProfiles( influencers ) + || isAffectedByEnabledFilters( influencers ) + || influencers.getBatchSize() != getBatchSize(); } default boolean isNotAffectedByInfluencers(LoadQueryInfluencers influencers) { return !isAffectedByEntityGraph( influencers ) - && !isAffectedByEnabledFetchProfiles( influencers ) - && !isAffectedByEnabledFilters( influencers ) - && influencers.getEnabledCascadingFetchProfile() == null; + && !isAffectedByEnabledFetchProfiles( influencers ) + && !isAffectedByEnabledFilters( influencers ) + && influencers.getBatchSize() == getBatchSize() + && influencers.getEnabledCascadingFetchProfile() == null; } + int getBatchSize(); + /** * Whether any of the "influencers" affect this loadable. */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java index 7d99b82f6c..4cf09c99c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java @@ -885,6 +885,11 @@ public class PluralAttributeMappingImpl } } + @Override + public int getBatchSize() { + return getCollectionDescriptor().getBatchSize(); + } + @Override public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) { return getCollectionDescriptor().isAffectedByEnabledFilters( influencers ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 14b7a88c12..0a06e294e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -6,17 +6,6 @@ */ package org.hibernate.persister.collection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; - import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; import org.hibernate.Filter; @@ -27,6 +16,7 @@ import org.hibernate.MappingException; import org.hibernate.QueryException; import org.hibernate.Remove; import org.hibernate.TransientObjectException; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cache.CacheException; import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.entry.CacheEntryStructure; @@ -124,7 +114,6 @@ import org.hibernate.sql.model.ast.RestrictedTableMutation; import org.hibernate.sql.model.internal.TableDeleteStandard; import org.hibernate.sql.model.jdbc.JdbcDeleteMutation; import org.hibernate.sql.model.jdbc.JdbcMutationOperation; -import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.type.CollectionType; @@ -132,6 +121,17 @@ import org.hibernate.type.CompositeType; import org.hibernate.type.EntityType; import org.hibernate.type.Type; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER; @@ -228,7 +228,7 @@ public abstract class AbstractCollectionPersister private final Comparator comparator; private CollectionLoader collectionLoader; - private volatile CollectionLoader standardCollectionLoader; +// private volatile CollectionLoader standardCollectionLoader; private CollectionElementLoaderByIndex collectionElementLoaderByIndex; private PluralAttributeMapping attributeMapping; @@ -570,14 +570,8 @@ public abstract class AbstractCollectionPersister // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // "mapping model" - if ( queryLoaderName != null ) { - final NamedQueryMemento namedQueryMemento = factory - .getQueryEngine() - .getNamedObjectRepository() - .resolve( factory, collectionBootDescriptor.getMetadata(), queryLoaderName ); - if ( namedQueryMemento == null ) { - throw new IllegalArgumentException( "Could not resolve named load-query [" + navigableRole + "] : " + queryLoaderName ); - } + if ( hasNamedQueryLoader() ) { + getNamedQueryMemento( collectionBootDescriptor.getMetadata() ); } tableMapping = buildCollectionTableMapping( collectionBootDescriptor, getTableName(), getCollectionSpaces() ); @@ -614,14 +608,12 @@ public abstract class AbstractCollectionPersister @Override public void postInstantiate() throws MappingException { - if ( queryLoaderName == null ) { - collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) ); + if ( hasNamedQueryLoader() ) { + // We pass null as metamodel because we did the initialization during construction already + collectionLoader = new CollectionLoaderNamedQuery( this, getNamedQueryMemento( null ) ); } else { - // We pass null as metamodel because we did the initialization during construction already - final NamedQueryMemento namedQueryMemento = factory.getQueryEngine().getNamedObjectRepository() - .resolve( factory, null, queryLoaderName ); - collectionLoader = new CollectionLoaderNamedQuery( this, namedQueryMemento ); + collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) ); } if ( attributeMapping.getIndexDescriptor() != null ) { @@ -635,6 +627,17 @@ public abstract class AbstractCollectionPersister logStaticSQL(); } + private NamedQueryMemento getNamedQueryMemento(MetadataImplementor bootModel) { + final NamedQueryMemento memento = + factory.getQueryEngine().getNamedObjectRepository() + .resolve( factory, bootModel, queryLoaderName ); + if ( memento == null ) { + throw new IllegalArgumentException( "Could not resolve named query '" + queryLoaderName + + "' for loading collection '" + getName() + "'" ); + } + return memento; + } + protected void logStaticSQL() { if ( !ModelMutationLogging.MODEL_MUTATION_LOGGER_DEBUG_ENABLED ) { return; @@ -676,51 +679,50 @@ public abstract class AbstractCollectionPersister // lazily initialize instance field via 'double-checked locking' // see https://en.wikipedia.org/wiki/Double-checked_locking on why 'volatile' and local copy is used - protected CollectionLoader getStandardCollectionLoader() { - CollectionLoader localCopy = standardCollectionLoader; - if ( localCopy == null ) { - synchronized (this) { - localCopy = standardCollectionLoader; - if ( localCopy == null ) { - if ( queryLoaderName != null ) { - localCopy = collectionLoader; - } - else { - localCopy = createCollectionLoader( new LoadQueryInfluencers( factory ) ); - } - standardCollectionLoader = localCopy; - } - } - } - return localCopy; +// protected CollectionLoader getStandardCollectionLoader() { +// CollectionLoader localCopy = standardCollectionLoader; +// if ( localCopy == null ) { +// synchronized (this) { +// localCopy = standardCollectionLoader; +// if ( localCopy == null ) { +// localCopy = createCollectionLoader( new LoadQueryInfluencers( factory ) ); +// standardCollectionLoader = localCopy; +// } +// } +// } +// return localCopy; +// } + + private boolean hasNamedQueryLoader() { + return queryLoaderName != null; + } + + public CollectionLoader getCollectionLoader() { + return collectionLoader; } protected CollectionLoader determineLoaderToUse(Object key, SharedSessionContractImplementor session) { - if ( queryLoaderName != null ) { + if ( hasNamedQueryLoader() ) { // if there is a user-specified loader, return that - return getStandardCollectionLoader(); + return getCollectionLoader(); } - final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); - if ( loadQueryInfluencers.effectiveSubselectFetchEnabled( this ) ) { + final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers(); + + if ( influencers.effectiveSubselectFetchEnabled( this ) ) { final CollectionLoader subSelectLoader = resolveSubSelectLoader( key, session ); if ( subSelectLoader != null ) { return subSelectLoader; } } - if ( !loadQueryInfluencers.hasEnabledFilters() - && !isAffectedByEnabledFetchProfiles( loadQueryInfluencers ) ) { - return getStandardCollectionLoader(); - } - else { - return createCollectionLoader( loadQueryInfluencers ); - } + return attributeMapping.isAffectedByInfluencers( influencers ) + ? createCollectionLoader( influencers ) + : getCollectionLoader(); } private CollectionLoader resolveSubSelectLoader(Object key, SharedSessionContractImplementor session) { final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final SubselectFetch subselect = persistenceContext.getBatchFetchQueue() .getSubselect( session.generateEntityKey( key, getOwnerEntityPersister() ) ); @@ -728,50 +730,47 @@ public abstract class AbstractCollectionPersister return null; } else { - // Take care of any entities that might have - // been evicted! + // Remove keys of any entities that have been evicted subselect.getResultingEntityKeys() .removeIf( entityKey -> !persistenceContext.containsEntity( entityKey ) ); - // Run a subquery loader return createSubSelectLoader( subselect, session ); } } protected CollectionLoader createSubSelectLoader(SubselectFetch subselect, SharedSessionContractImplementor session) { - //noinspection RedundantCast - return new CollectionLoaderSubSelectFetch( attributeMapping, (DomainResult) null, subselect, session ); + return new CollectionLoaderSubSelectFetch( attributeMapping, null, subselect, session ); } +// +// private CollectionLoader reusableCollectionLoader; +// +// protected CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { +// if ( canUseReusableCollectionLoader( loadQueryInfluencers ) ) { +// if ( reusableCollectionLoader == null ) { +// reusableCollectionLoader = generateCollectionLoader( new LoadQueryInfluencers( factory ) ); +// } +// return reusableCollectionLoader; +// } +// else { +// // create a one-off +// return generateCollectionLoader( loadQueryInfluencers ); +// } +// } +// +// private boolean canUseReusableCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { +// // we can reuse it so long as none of the enabled influencers affect it +// return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers ); +// } - private CollectionLoader reusableCollectionLoader; - - protected CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { - if ( canUseReusableCollectionLoader( loadQueryInfluencers ) ) { - if ( reusableCollectionLoader == null ) { - reusableCollectionLoader = generateCollectionLoader( new LoadQueryInfluencers( factory ) ); - } - return reusableCollectionLoader; - } - else { - // create a one-off - return generateCollectionLoader( loadQueryInfluencers ); - } - } - - private boolean canUseReusableCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { - // we can reuse it so long as none of the enabled influencers affect it - return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers ); - } - - private CollectionLoader generateCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { + private CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) { final int batchSize = loadQueryInfluencers.effectiveBatchSize( this ); - return getFactory().getServiceRegistry() + return factory.getServiceRegistry() .getService( BatchLoaderFactory.class ) - .createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, getFactory() ); + .createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, factory ); } else { - return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, getFactory() ); + return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, factory ); } } @@ -1564,16 +1563,13 @@ public abstract class AbstractCollectionPersister @Override public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers) { - if ( affectingFetchProfiles == null ) { - return false; - } - - for ( Map.Entry entry : affectingFetchProfiles.entrySet() ) { - if ( influencers.isFetchProfileEnabled( entry.getKey() ) ) { - return true; + if ( affectingFetchProfiles != null && influencers.hasEnabledFetchProfiles() ) { + for ( String profileName : affectingFetchProfiles.keySet() ) { + if ( influencers.isFetchProfileEnabled( profileName ) ) { + return true; + } } } - return false; } @@ -1581,11 +1577,12 @@ public abstract class AbstractCollectionPersister public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) { if ( influencers.hasEnabledFilters() ) { final Map enabledFilters = influencers.getEnabledFilters(); - return ( filterHelper != null && filterHelper.isAffectedBy( enabledFilters ) ) - || ( manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters ) ); + return filterHelper != null && filterHelper.isAffectedBy( enabledFilters ) + || manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters ); + } + else { + return false; } - - return false; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 73e8616657..7cf165d604 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -44,6 +44,7 @@ import org.hibernate.Remove; import org.hibernate.StaleObjectStateException; import org.hibernate.StaleStateException; import org.hibernate.boot.Metadata; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; @@ -301,6 +302,7 @@ import static org.hibernate.internal.util.collections.ArrayHelper.toTypeArray; import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; import static org.hibernate.internal.util.collections.CollectionHelper.setOfSize; import static org.hibernate.internal.util.collections.CollectionHelper.toSmallList; +import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.supportsSqlArrayType; import static org.hibernate.metamodel.RepresentationMode.POJO; import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR; import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR; @@ -327,8 +329,8 @@ public abstract class AbstractEntityPersister private final String sqlAliasStem; - private final SingleIdEntityLoader singleIdLoader; - private final MultiIdEntityLoader multiIdLoader; + private SingleIdEntityLoader singleIdLoader; + private MultiIdEntityLoader multiIdLoader; private NaturalIdLoader naturalIdLoader; private MultiNaturalIdLoader multiNaturalIdLoader; @@ -432,6 +434,8 @@ public abstract class AbstractEntityPersister protected AttributeMappingsMap declaredAttributeMappings = AttributeMappingsMap.builder().build(); protected AttributeMappingsList staticFetchableList; + private final String queryLoaderName; + private BeforeExecutionGenerator versionGenerator; protected ReflectionOptimizer.AccessOptimizer accessOptimizer; @@ -524,22 +528,7 @@ public abstract class AbstractEntityPersister final String rowId = persistentClass.getRootTable().getRowId(); rowIdName = rowId == null ? null : dialect.rowId( rowId ); - if ( persistentClass.getLoaderName() != null ) { - // We must resolve the named query on-demand through the boot model because it isn't initialized yet - final NamedQueryMemento namedQueryMemento = - factory.getQueryEngine().getNamedObjectRepository() - .resolve( factory, creationContext.getBootModel(), persistentClass.getLoaderName() ); - if ( namedQueryMemento == null ) { - throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName() - + "] : " + persistentClass.getLoaderName() ); - } - singleIdLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, namedQueryMemento ); - } - else { - singleIdLoader = createSingleIdEntityLoader( new LoadQueryInfluencers( factory ) ); - } - - multiIdLoader = buildMultiIdLoader( persistentClass ); + queryLoaderName = persistentClass.getLoaderName(); final TypeConfiguration typeConfiguration = creationContext.getTypeConfiguration(); final SqmFunctionRegistry functionRegistry = creationContext.getFunctionRegistry(); @@ -805,12 +794,29 @@ public abstract class AbstractEntityPersister fullDiscriminatorSQLValues = toStringArray( sqlValues ); fullDiscriminatorValues = toObjectArray( values ); + + if ( hasNamedQueryLoader() ) { + getNamedQueryMemento( creationContext.getBootModel() ); + } + } + + private NamedQueryMemento getNamedQueryMemento(MetadataImplementor bootModel) { + final NamedQueryMemento memento = + factory.getQueryEngine().getNamedObjectRepository() + .resolve( factory, bootModel, queryLoaderName ); + if ( memento == null ) { + throw new IllegalArgumentException( "Could not resolve named query '" + queryLoaderName + + "' for loading entity '" + getEntityName() + "'" ); + } + return memento; } private SingleIdEntityLoader createSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) { if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) { final int batchSize = loadQueryInfluencers.effectiveBatchSize( this ); - return createBatchingIdEntityLoader( this, batchSize, factory ); + return factory.getServiceRegistry() + .getService( BatchLoaderFactory.class ) + .createEntityBatchLoader( batchSize, this, factory ); } else { return new SingleIdEntityLoaderStandardImpl<>( this, factory ); @@ -836,12 +842,14 @@ public abstract class AbstractEntityPersister return entityNameByTableNameMap; } - private MultiIdEntityLoader buildMultiIdLoader(PersistentClass persistentClass) { - if ( persistentClass.getIdentifier() instanceof BasicValue - && MultiKeyLoadHelper.supportsSqlArrayType( factory.getServiceRegistry().getService( JdbcServices.class ).getDialect() ) ) { + private MultiIdEntityLoader buildMultiIdLoader() { + if ( getIdentifierType() instanceof BasicType + && supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ) { return new MultiIdEntityLoaderArrayParam<>( this, factory ); } - return new MultiIdEntityLoaderStandard<>( this, persistentClass, factory ); + else { + return new MultiIdEntityLoaderStandard<>( this, identifierColumnSpan, factory ); + } } private String getIdentitySelectString(Dialect dialect) { @@ -1051,15 +1059,6 @@ public abstract class AbstractEntityPersister return tableNames; } - private static SingleIdEntityLoader createBatchingIdEntityLoader( - EntityMappingType entityDescriptor, - int domainBatchSize, - SessionFactoryImplementor factory) { - return factory.getServiceRegistry() - .getService( BatchLoaderFactory.class ) - .createEntityBatchLoader( domainBatchSize, entityDescriptor, factory ); - } - /** * We might need to use cache invalidation if we have formulas, * dynamic update, or secondary tables. @@ -3390,8 +3389,28 @@ public abstract class AbstractEntityPersister @Override public final void postInstantiate() throws MappingException { doLateInit(); - prepareLoader( singleIdLoader ); + if ( hasNamedQueryLoader() ) { + // We must resolve the named query on-demand through the boot model because it isn't initialized yet + final NamedQueryMemento memento = getNamedQueryMemento( null ); + singleIdLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, memento ); + prepareLoader( singleIdLoader ); + } + else { + singleIdLoader = createAndPrepareSingleIdEntityLoader( new LoadQueryInfluencers( factory ) ); + } + multiIdLoader = buildAndPrepareMultiIdLoader(); + } + + private MultiIdEntityLoader buildAndPrepareMultiIdLoader() { + MultiIdEntityLoader multiIdLoader = buildMultiIdLoader(); prepareLoader( multiIdLoader ); + return multiIdLoader; + } + + private SingleIdEntityLoader createAndPrepareSingleIdEntityLoader(LoadQueryInfluencers influencers) { + SingleIdEntityLoader singleIdLoader = createSingleIdEntityLoader( influencers ); + prepareLoader( singleIdLoader ); + return singleIdLoader; } private void prepareLoader(Loader loader) { @@ -3430,14 +3449,29 @@ public abstract class AbstractEntityPersister LOG.tracev( "Fetching entity: {0}", infoString( this, id, getFactory() ) ); } - if ( optionalObject == null ) { - return singleIdLoader.load( id, lockOptions, readOnly, session ); + final SingleIdEntityLoader loader = determineLoaderToUse( session ); + return optionalObject == null + ? loader.load( id, lockOptions, readOnly, session ) + : loader.load( id, optionalObject, lockOptions, readOnly, session ); + } + + protected SingleIdEntityLoader determineLoaderToUse(SharedSessionContractImplementor session) { + if ( hasNamedQueryLoader() ) { + return getSingleIdLoader(); } else { - return singleIdLoader.load( id, optionalObject, lockOptions, readOnly, session ); + final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers(); + // no subselect fetching for entities for now + return isAffectedByInfluencers( influencers ) + ? createAndPrepareSingleIdEntityLoader( influencers ) + : getSingleIdLoader(); } } + private boolean hasNamedQueryLoader() { + return queryLoaderName != null; + } + public SingleIdEntityLoader getSingleIdLoader() { return singleIdLoader; } @@ -3461,7 +3495,7 @@ public abstract class AbstractEntityPersister loaded = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( loadEvent, this, entityKey ); } if ( loaded == null ) { - loaded = singleIdLoader.load( identifier, entity, LockOptions.NONE, session ); + loaded = determineLoaderToUse( session ).load( identifier, entity, LockOptions.NONE, session ); } if ( loaded == null ) { @@ -3517,7 +3551,7 @@ public abstract class AbstractEntityPersister @Override public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers loadQueryInfluencers) { - if ( affectingFetchProfileNames != null ) { + if ( affectingFetchProfileNames != null && loadQueryInfluencers.hasEnabledFetchProfiles() ) { for ( String profileName : loadQueryInfluencers.getEnabledFetchProfileNames() ) { if ( affectingFetchProfileNames.contains( profileName ) ) { return true; @@ -3529,7 +3563,7 @@ public abstract class AbstractEntityPersister @Override public boolean isAffectedByEnabledFilters(LoadQueryInfluencers loadQueryInfluencers) { - if ( loadQueryInfluencers.hasEnabledFilters() && filterHelper != null ) { + if ( filterHelper != null && loadQueryInfluencers.hasEnabledFilters() ) { if ( filterHelper.isAffectedBy( loadQueryInfluencers.getEnabledFilters() ) ) { return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java index e9a32df372..09dd8021b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java @@ -16,6 +16,7 @@ import java.util.function.Consumer; import org.hibernate.Incubating; import org.hibernate.cache.MutableCacheKeyBuilder; import org.hibernate.engine.OptimisticLockStyle; +import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.IndexedConsumer; import org.hibernate.loader.ast.spi.MultiNaturalIdLoader; @@ -728,4 +729,19 @@ public class AnonymousTupleEntityValuedModelPart public boolean containsTableReference(String tableExpression) { return ( (TableGroupProducer) delegate ).containsTableReference( tableExpression ); } + + @Override + public int getBatchSize() { + return -1; + } + + @Override + public boolean isAffectedByInfluencers(LoadQueryInfluencers influencers) { + return false; + } + + @Override + public boolean isNotAffectedByInfluencers(LoadQueryInfluencers influencers) { + return true; + } }