HHH-16651 make persisters return adapted loaders for session batch size

This commit is contained in:
Gavin 2023-05-21 18:37:49 +02:00 committed by Gavin King
parent 3097c47b3d
commit bbd8df93ca
11 changed files with 222 additions and 190 deletions

View File

@ -46,7 +46,7 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
public CollectionLoaderSubSelectFetch(
PluralAttributeMapping attributeMapping,
DomainResult cachedDomainResult,
DomainResult<?> cachedDomainResult,
SubselectFetch subselect,
SharedSessionContractImplementor session) {
this.attributeMapping = attributeMapping;

View File

@ -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<T>
@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

View File

@ -56,16 +56,18 @@ public class EntityBatchLoaderInPredicate<T>
/**
* @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(

View File

@ -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<E> extends AbstractMultiIdEntityLoade
return ids;
}
private <X> X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) {
private <X> X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) {
//noinspection unchecked
return (X[]) Array.newInstance( getIdentifierMapping().getJavaType().getJavaTypeClass(), length );
}
@ -393,14 +391,9 @@ public class MultiIdEntityLoaderArrayParam<E> 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()

View File

@ -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<T> 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;
}

View File

@ -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 <T> EntityBatchLoader<T> 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 );
}
}
}

View File

@ -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.
*/

View File

@ -885,6 +885,11 @@ public class PluralAttributeMappingImpl
}
}
@Override
public int getBatchSize() {
return getCollectionDescriptor().getBatchSize();
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
return getCollectionDescriptor().isAffectedByEnabledFilters( influencers );

View File

@ -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<String, Fetch.Style> 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<String, Filter> 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

View File

@ -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<Object> buildMultiIdLoader(PersistentClass persistentClass) {
if ( persistentClass.getIdentifier() instanceof BasicValue
&& MultiKeyLoadHelper.supportsSqlArrayType( factory.getServiceRegistry().getService( JdbcServices.class ).getDialect() ) ) {
private MultiIdEntityLoader<Object> 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<Object> buildAndPrepareMultiIdLoader() {
MultiIdEntityLoader<Object> 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;
}

View File

@ -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;
}
}