further cleanups on multi id loaders

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-10-26 10:12:03 +02:00
parent 6c5f577223
commit 10c83d8370
4 changed files with 163 additions and 163 deletions

View File

@ -6,22 +6,27 @@ package org.hibernate.loader.ast.internal;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LoadEvent; import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener; import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.spi.MultiIdEntityLoader; import org.hibernate.loader.ast.spi.MultiIdEntityLoader;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic; import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
/** /**
* Base support for {@link MultiIdEntityLoader} implementations. * Base support for {@link MultiIdEntityLoader} implementations.
@ -51,6 +56,18 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
return identifierMapping; return identifierMapping;
} }
protected JdbcServices getJdbcServices() {
return getSessionFactory().getJdbcServices();
}
protected SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
return getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
}
protected JdbcSelectExecutor getJdbcSelectExecutor() {
return getJdbcServices().getJdbcSelectExecutor();
}
@Override @Override
public EntityMappingType getLoadable() { public EntityMappingType getLoadable() {
return getEntityDescriptor(); return getEntityDescriptor();
@ -71,9 +88,8 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
Object[] ids, Object[] ids,
MultiIdLoadOptions loadOptions, MultiIdLoadOptions loadOptions,
EventSource session) { EventSource session) {
if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef( "#performOrderedMultiLoad(`%s`, ..)", MULTI_KEY_LOAD_LOGGER.tracef( "#performOrderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() );
getLoadable().getEntityName() );
} }
assert loadOptions.isOrderReturnEnabled(); assert loadOptions.isOrderReturnEnabled();
@ -87,7 +103,7 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
final int maxBatchSize = maxBatchSize( ids, loadOptions ); final int maxBatchSize = maxBatchSize( ids, loadOptions );
final List<Object> result = CollectionHelper.arrayList( ids.length ); final List<Object> result = arrayList( ids.length );
final List<Object> idsInBatch = new ArrayList<>(); final List<Object> idsInBatch = new ArrayList<>();
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>(); final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
@ -146,7 +162,7 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
getLoadable().getJavaType().getJavaTypeClass().getName(), getLoadable().getJavaType().getJavaTypeClass().getName(),
lockOptions, lockOptions,
session, session,
LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) getReadOnlyFromLoadQueryInfluencers( session )
); );
Object managedEntity = null; Object managedEntity = null;

View File

@ -10,13 +10,11 @@ import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LoadEvent; import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener; import org.hibernate.event.spi.LoadEventListener;
@ -28,6 +26,7 @@ import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
@ -36,6 +35,7 @@ import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList; import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl; import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ManagedResultConsumer; import org.hibernate.sql.results.spi.ManagedResultConsumer;
@ -43,8 +43,15 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static org.hibernate.engine.internal.BatchFetchQueueHelper.removeBatchLoadableEntityKey;
import static org.hibernate.engine.spi.SubselectFetch.createRegistrationHandler;
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic; import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
import static org.hibernate.loader.ast.internal.LoaderHelper.loadByArrayParameter;
import static org.hibernate.loader.ast.internal.LoaderSelectBuilder.createSelectBySingleArrayParameter;
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.resolveArrayJdbcMapping;
import static org.hibernate.sql.exec.spi.JdbcParameterBindings.NO_BINDINGS;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -52,13 +59,13 @@ import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFrom
public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoader<E> implements SqlArrayMultiKeyLoader { public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoader<E> implements SqlArrayMultiKeyLoader {
private final JdbcMapping arrayJdbcMapping; private final JdbcMapping arrayJdbcMapping;
private final JdbcParameter jdbcParameter; private final JdbcParameter jdbcParameter;
private final int idJdbcTypeCount;
public MultiIdEntityLoaderArrayParam(EntityMappingType entityDescriptor, int identifierColumnSpan, SessionFactoryImplementor sessionFactory) { public MultiIdEntityLoaderArrayParam(
EntityMappingType entityDescriptor,
SessionFactoryImplementor sessionFactory) {
super( entityDescriptor, sessionFactory ); super( entityDescriptor, sessionFactory );
this.idJdbcTypeCount = identifierColumnSpan;
final Class<?> arrayClass = createTypedArray( 0 ).getClass(); final Class<?> arrayClass = createTypedArray( 0 ).getClass();
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( arrayJdbcMapping = resolveArrayJdbcMapping(
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ), getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ),
getIdentifierMapping().getJdbcMapping(), getIdentifierMapping().getJdbcMapping(),
arrayClass, arrayClass,
@ -83,7 +90,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
// the element value at this position in the result List should be // the element value at this position in the result List should be
// the EntityKey for that entity - reuse it // the EntityKey for that entity - reuse it
final EntityKey entityKey = (EntityKey) result.get( position ); final EntityKey entityKey = (EntityKey) result.get( position );
BatchFetchQueueHelper.removeBatchLoadableEntityKey( entityKey, session ); removeBatchLoadableEntityKey( entityKey, session );
Object entity = persistenceContext.getEntity( entityKey ); Object entity = persistenceContext.getEntity( entityKey );
if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) { if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) {
// make sure it is not DELETED // make sure it is not DELETED
@ -102,28 +109,20 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
@Override @Override
protected int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions) { protected int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions) {
if ( loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0 ) { final Integer explicitBatchSize = loadOptions.getBatchSize();
return loadOptions.getBatchSize(); return explicitBatchSize != null && explicitBatchSize > 0
} ? explicitBatchSize
else { // disable batching by default
// disable batching by default : ids.length;
return ids.length;
// return getSessionFactory().getJdbcServices().getJdbcEnvironment().getDialect()
// .getBatchLoadSizingStrategy().determineOptimalBatchLoadSize(
// idJdbcTypeCount,
// ids.length,
// getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled()
// );
}
} }
@Override @Override
protected void loadEntitiesById( protected void loadEntitiesById(
List<Object> idsToLoadFromDatabase, List<Object> idsInBatch,
LockOptions lockOptions, LockOptions lockOptions,
MultiIdLoadOptions loadOptions, MultiIdLoadOptions loadOptions,
EventSource session) { EventSource session) {
final SelectStatement sqlAst = LoaderSelectBuilder.createSelectBySingleArrayParameter( final SelectStatement sqlAst = createSelectBySingleArrayParameter(
getLoadable(), getLoadable(),
getIdentifierMapping(), getIdentifierMapping(),
session.getLoadQueryInfluencers(), session.getLoadQueryInfluencers(),
@ -131,42 +130,31 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
jdbcParameter, jdbcParameter,
getSessionFactory() getSessionFactory()
); );
final JdbcOperationQuerySelect jdbcSelectOperation = getSessionFactory().getJdbcServices()
.getJdbcEnvironment()
.getSqlAstTranslatorFactory()
.buildSelectTranslator( getSessionFactory(), sqlAst )
.translate( JdbcParameterBindings.NO_BINDINGS, QueryOptions.NONE );
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(1); final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(1);
jdbcParameterBindings.addBinding( jdbcParameterBindings.addBinding( jdbcParameter,
jdbcParameter, new JdbcParameterBindingImpl( arrayJdbcMapping, idsInBatch.toArray( createTypedArray(0) ) ) );
new JdbcParameterBindingImpl( arrayJdbcMapping, idsToLoadFromDatabase.toArray( createTypedArray(0 ) ) )
);
final PersistenceContext persistenceContext = session.getPersistenceContext(); getJdbcSelectExecutor().executeQuery(
final BatchFetchQueue batchFetchQueue = persistenceContext.getBatchFetchQueue(); getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
.translate( NO_BINDINGS, QueryOptions.NONE ),
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
batchFetchQueue,
sqlAst,
JdbcParametersList.singleton( jdbcParameter ),
jdbcParameterBindings
);
session.getJdbcServices().getJdbcSelectExecutor().executeQuery(
jdbcSelectOperation,
jdbcParameterBindings, jdbcParameterBindings,
new ExecutionContextWithSubselectFetchHandler( session, new ExecutionContextWithSubselectFetchHandler(
subSelectFetchableKeysHandler, session,
createRegistrationHandler(
session.getPersistenceContext().getBatchFetchQueue(),
sqlAst,
JdbcParametersList.singleton( jdbcParameter ),
jdbcParameterBindings
),
TRUE.equals( loadOptions.getReadOnly( session ) ) ), TRUE.equals( loadOptions.getReadOnly( session ) ) ),
RowTransformerStandardImpl.instance(), RowTransformerStandardImpl.instance(),
null, null,
idsToLoadFromDatabase.size(), idsInBatch.size(),
ManagedResultConsumer.INSTANCE ManagedResultConsumer.INSTANCE
); );
} }
@Override @Override
protected <K> List<E> performUnorderedMultiLoad( protected <K> List<E> performUnorderedMultiLoad(
K[] ids, K[] ids,
@ -180,7 +168,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
} }
final List<E> result = CollectionHelper.arrayList( ids.length ); final List<E> result = CollectionHelper.arrayList( ids.length );
final LockOptions lockOptions = (loadOptions.getLockOptions() == null) final LockOptions lockOptions = loadOptions.getLockOptions() == null
? new LockOptions( LockMode.NONE ) ? new LockOptions( LockMode.NONE )
: loadOptions.getLockOptions(); : loadOptions.getLockOptions();
@ -198,7 +186,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
return result; return result;
} }
final SelectStatement sqlAst = LoaderSelectBuilder.createSelectBySingleArrayParameter( final SelectStatement sqlAst = createSelectBySingleArrayParameter(
getLoadable(), getLoadable(),
getIdentifierMapping(), getIdentifierMapping(),
session.getLoadQueryInfluencers(), session.getLoadQueryInfluencers(),
@ -206,13 +194,11 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
jdbcParameter, jdbcParameter,
getSessionFactory() getSessionFactory()
); );
final JdbcOperationQuerySelect jdbcSelectOperation = getSessionFactory().getJdbcServices() final JdbcOperationQuerySelect jdbcSelectOperation =
.getJdbcEnvironment() getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
.getSqlAstTranslatorFactory() .translate( NO_BINDINGS, QueryOptions.NONE );
.buildSelectTranslator( getSessionFactory(), sqlAst )
.translate( JdbcParameterBindings.NO_BINDINGS, QueryOptions.NONE );
final List<E> databaseResults = LoaderHelper.loadByArrayParameter( final List<E> databaseResults = loadByArrayParameter(
idsToLoadFromDatabase, idsToLoadFromDatabase,
sqlAst, sqlAst,
jdbcSelectOperation, jdbcSelectOperation,
@ -236,7 +222,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
continue; continue;
} }
// found or not, remove the key from the batch-fetch queue // found or not, remove the key from the batch-fetch queue
BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, getLoadable(), session ); removeBatchLoadableEntityKey( id, getLoadable(), session );
} }
return result; return result;
@ -272,7 +258,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
getLoadable().getJavaType().getJavaTypeClass().getName(), getLoadable().getJavaType().getJavaTypeClass().getName(),
lockOptions, lockOptions,
session, session,
LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) getReadOnlyFromLoadQueryInfluencers( session )
); );
Object managedEntity = null; Object managedEntity = null;

View File

@ -6,11 +6,11 @@ package org.hibernate.loader.ast.internal;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
@ -20,26 +20,29 @@ import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LoadEvent; import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener; import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry; import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList; import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl; import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer; import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.jboss.logging.Logger;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hibernate.engine.spi.SubselectFetch.createRegistrationHandler;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic; import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
import static org.hibernate.loader.ast.internal.LoaderSelectBuilder.createSelect;
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
/** /**
* Standard MultiIdEntityLoader * Standard MultiIdEntityLoader
@ -47,7 +50,6 @@ import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFrom
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<T> { public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<T> {
private static final Logger log = Logger.getLogger( MultiIdEntityLoaderStandard.class );
private final int idJdbcTypeCount; private final int idJdbcTypeCount;
@ -57,10 +59,17 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
super( entityDescriptor, sessionFactory ); super( entityDescriptor, sessionFactory );
this.idJdbcTypeCount = idColumnSpan; this.idJdbcTypeCount = idColumnSpan;
assert idJdbcTypeCount > 0; assert idJdbcTypeCount > 0;
} }
private boolean isInClauseParameterPaddingEnabled() {
return getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled();
}
private MultiKeyLoadSizingStrategy getBatchLoadSizingStrategy() {
return getJdbcServices().getJdbcEnvironment().getDialect().getBatchLoadSizingStrategy();
}
@Override @Override
protected void handleResults( protected void handleResults(
MultiIdLoadOptions loadOptions, MultiIdLoadOptions loadOptions,
@ -90,17 +99,12 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
@Override @Override
protected int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions) { protected int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions) {
if ( loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0 ) { final Integer explicitBatchSize = loadOptions.getBatchSize();
return loadOptions.getBatchSize(); return explicitBatchSize != null && explicitBatchSize > 0
} ? explicitBatchSize
else { : getBatchLoadSizingStrategy()
return getSessionFactory().getJdbcServices().getJdbcEnvironment().getDialect() .determineOptimalBatchLoadSize( idJdbcTypeCount, ids.length,
.getBatchLoadSizingStrategy().determineOptimalBatchLoadSize( isInClauseParameterPaddingEnabled() );
idJdbcTypeCount,
ids.length,
getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled()
);
}
} }
@Override @Override
@ -111,7 +115,6 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
EventSource session) { EventSource session) {
assert idsInBatch != null; assert idsInBatch != null;
assert !idsInBatch.isEmpty(); assert !idsInBatch.isEmpty();
listEntitiesById( idsInBatch, lockOptions, loadOptions, session ); listEntitiesById( idsInBatch, lockOptions, loadOptions, session );
} }
@ -121,85 +124,84 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
MultiIdLoadOptions loadOptions, MultiIdLoadOptions loadOptions,
EventSource session) { EventSource session) {
final int numberOfIdsInBatch = idsInBatch.size(); final int numberOfIdsInBatch = idsInBatch.size();
if ( numberOfIdsInBatch == 1 ) { return numberOfIdsInBatch == 1
return performSingleMultiLoad( idsInBatch.get( 0 ), lockOptions, session ); ? performSingleMultiLoad( idsInBatch.get( 0 ), lockOptions, session )
: performRegularMultiLoad( idsInBatch, lockOptions, loadOptions, session, numberOfIdsInBatch );
}
private List<T> performRegularMultiLoad(
List<Object> idsInBatch,
LockOptions lockOptions,
MultiIdLoadOptions loadOptions,
EventSource session,
int numberOfIdsInBatch) {
if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
MULTI_KEY_LOAD_LOGGER.tracef( "#loadEntitiesById(`%s`, `%s`, ..)",
getLoadable().getEntityName(), numberOfIdsInBatch );
} }
else {
if ( log.isTraceEnabled() ) {
log.tracef( "#loadEntitiesById(`%s`, `%s`, ..)", getLoadable().getEntityName(), numberOfIdsInBatch );
}
final JdbcParametersList.Builder jdbcParametersBuilder = final JdbcParametersList.Builder jdbcParametersBuilder =
JdbcParametersList.newBuilder( numberOfIdsInBatch * idJdbcTypeCount ); JdbcParametersList.newBuilder( numberOfIdsInBatch * idJdbcTypeCount );
final SelectStatement sqlAst = LoaderSelectBuilder.createSelect( final SelectStatement sqlAst = createSelect(
getLoadable(), getLoadable(),
// null here means to select everything // null here means to select everything
null, null,
getLoadable().getIdentifierMapping(),
null,
numberOfIdsInBatch,
session.getLoadQueryInfluencers(),
lockOptions,
jdbcParametersBuilder::add,
getSessionFactory()
);
final JdbcParametersList jdbcParameters = jdbcParametersBuilder.build();
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( jdbcParameters.size() );
int offset = 0;
for ( int i = 0; i < numberOfIdsInBatch; i++ ) {
offset += jdbcParameterBindings.registerParametersForEachJdbcValue(
idsInBatch.get( i ),
offset,
getLoadable().getIdentifierMapping(), getLoadable().getIdentifierMapping(),
null, jdbcParameters,
numberOfIdsInBatch, session
session.getLoadQueryInfluencers(),
lockOptions,
jdbcParametersBuilder::add,
getSessionFactory()
);
JdbcParametersList jdbcParameters = jdbcParametersBuilder.build();
final SqlAstTranslatorFactory sqlAstTranslatorFactory =
getSessionFactory().getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( jdbcParameters.size() );
int offset = 0;
for ( int i = 0; i < numberOfIdsInBatch; i++ ) {
final Object id = idsInBatch.get( i );
offset += jdbcParameterBindings.registerParametersForEachJdbcValue(
id,
offset,
getLoadable().getIdentifierMapping(),
jdbcParameters,
session
);
}
// we should have used all the JdbcParameter references (created bindings for all)
assert offset == jdbcParameters.size();
final JdbcOperationQuerySelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( getSessionFactory(), sqlAst )
.translate( jdbcParameterBindings, QueryOptions.NONE );
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
if ( session.getLoadQueryInfluencers().hasSubselectLoadableCollections( getLoadable().getEntityPersister() ) ) {
subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
session.getPersistenceContext().getBatchFetchQueue(),
sqlAst,
jdbcParameters,
jdbcParameterBindings
);
}
else {
subSelectFetchableKeysHandler = null;
}
return session.getJdbcServices().getJdbcSelectExecutor().list(
jdbcSelect,
jdbcParameterBindings,
new ExecutionContextWithSubselectFetchHandler( session,
subSelectFetchableKeysHandler,
TRUE.equals( loadOptions.getReadOnly( session ) ) ),
RowTransformerStandardImpl.instance(),
null,
ListResultsConsumer.UniqueSemantic.FILTER,
idsInBatch.size()
); );
} }
// we should have used all the JdbcParameter references (created bindings for all)
assert offset == jdbcParameters.size();
return getJdbcSelectExecutor().list(
getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
.translate( jdbcParameterBindings, QueryOptions.NONE ),
jdbcParameterBindings,
new ExecutionContextWithSubselectFetchHandler(
session,
fetchableKeysHandler( session, sqlAst, jdbcParameters, jdbcParameterBindings ),
TRUE.equals( loadOptions.getReadOnly( session ) )
),
RowTransformerStandardImpl.instance(),
null,
ListResultsConsumer.UniqueSemantic.FILTER,
idsInBatch.size()
);
}
private SubselectFetch.RegistrationHandler fetchableKeysHandler(
EventSource session,
SelectStatement sqlAst,
JdbcParametersList jdbcParameters,
JdbcParameterBindings jdbcParameterBindings) {
final BatchFetchQueue batchFetchQueue = session.getPersistenceContext().getBatchFetchQueue();
return session.getLoadQueryInfluencers().hasSubselectLoadableCollections( getLoadable().getEntityPersister() )
? createRegistrationHandler( batchFetchQueue, sqlAst, jdbcParameters, jdbcParameterBindings )
: null;
} }
private List<T> performSingleMultiLoad(Object id, LockOptions lockOptions, SharedSessionContractImplementor session) { private List<T> performSingleMultiLoad(Object id, LockOptions lockOptions, SharedSessionContractImplementor session) {
//noinspection unchecked @SuppressWarnings("unchecked")
T loaded = (T) getLoadable().getEntityPersister().load( id, null, lockOptions, session ); T loaded = (T) getLoadable().getEntityPersister().load( id, null, lockOptions, session );
return Collections.singletonList( loaded ); return singletonList( loaded );
} }
@Override @Override
@ -210,11 +212,11 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
assert !loadOptions.isOrderReturnEnabled(); assert !loadOptions.isOrderReturnEnabled();
assert ids != null; assert ids != null;
if ( log.isTraceEnabled() ) { if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
log.tracef( "#performUnorderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() ); MULTI_KEY_LOAD_LOGGER.tracef( "#performUnorderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() );
} }
final List<T> result = CollectionHelper.arrayList( ids.length ); final List<T> result = arrayList( ids.length );
final LockOptions lockOptions = loadOptions.getLockOptions() == null final LockOptions lockOptions = loadOptions.getLockOptions() == null
? new LockOptions( LockMode.NONE ) ? new LockOptions( LockMode.NONE )
@ -241,7 +243,7 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
getLoadable().getJavaType().getJavaTypeClass().getName(), getLoadable().getJavaType().getJavaTypeClass().getName(),
lockOptions, lockOptions,
session, session,
LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) getReadOnlyFromLoadQueryInfluencers( session )
); );
Object managedEntity = null; Object managedEntity = null;
@ -303,27 +305,23 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
maxBatchSize = loadOptions.getBatchSize(); maxBatchSize = loadOptions.getBatchSize();
} }
else { else {
maxBatchSize = session.getJdbcServices().getJdbcEnvironment().getDialect().getBatchLoadSizingStrategy().determineOptimalBatchLoadSize( maxBatchSize = getBatchLoadSizingStrategy().determineOptimalBatchLoadSize(
getIdentifierMapping().getJdbcTypeCount(), getIdentifierMapping().getJdbcTypeCount(),
numberOfIdsLeft, numberOfIdsLeft,
getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled() isInClauseParameterPaddingEnabled()
); );
} }
int idPosition = 0; int idPosition = 0;
while ( numberOfIdsLeft > 0 ) { while ( numberOfIdsLeft > 0 ) {
final int batchSize = Math.min( numberOfIdsLeft, maxBatchSize ); final int batchSize = Math.min( numberOfIdsLeft, maxBatchSize );
final Object[] idsInBatch = new Object[ batchSize ]; final Object[] idsInBatch = new Object[ batchSize ];
System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize ); System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize );
result.addAll( listEntitiesById( asList( idsInBatch ), lockOptions, loadOptions, session ) ); result.addAll( listEntitiesById( asList( idsInBatch ), lockOptions, loadOptions, session ) );
numberOfIdsLeft = numberOfIdsLeft - batchSize; numberOfIdsLeft = numberOfIdsLeft - batchSize;
idPosition += batchSize; idPosition += batchSize;
} }
return result; return result;
} }
} }

View File

@ -857,7 +857,7 @@ public abstract class AbstractEntityPersister
protected MultiIdEntityLoader<Object> buildMultiIdLoader() { protected MultiIdEntityLoader<Object> buildMultiIdLoader() {
final Dialect dialect = factory.getJdbcServices().getDialect(); final Dialect dialect = factory.getJdbcServices().getDialect();
return getIdentifierType() instanceof BasicType && supportsSqlArrayType( dialect ) return getIdentifierType() instanceof BasicType && supportsSqlArrayType( dialect )
? new MultiIdEntityLoaderArrayParam<>( this, identifierColumnSpan, factory ) ? new MultiIdEntityLoaderArrayParam<>( this, factory )
: new MultiIdEntityLoaderStandard<>( this, identifierColumnSpan, factory ); : new MultiIdEntityLoaderStandard<>( this, identifierColumnSpan, factory );
} }