diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractMultiIdEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractMultiIdEntityLoader.java index 06bbafbeea..84f089c297 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractMultiIdEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractMultiIdEntityLoader.java @@ -6,22 +6,27 @@ package org.hibernate.loader.ast.internal; import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.spi.EventSource; 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.MultiIdEntityLoader; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; 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 java.util.ArrayList; 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.LoaderHelper.getReadOnlyFromLoadQueryInfluencers; +import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER; /** * Base support for {@link MultiIdEntityLoader} implementations. @@ -51,6 +56,18 @@ public abstract class AbstractMultiIdEntityLoader implements MultiIdEntityLoa return identifierMapping; } + protected JdbcServices getJdbcServices() { + return getSessionFactory().getJdbcServices(); + } + + protected SqlAstTranslatorFactory getSqlAstTranslatorFactory() { + return getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory(); + } + + protected JdbcSelectExecutor getJdbcSelectExecutor() { + return getJdbcServices().getJdbcSelectExecutor(); + } + @Override public EntityMappingType getLoadable() { return getEntityDescriptor(); @@ -71,9 +88,8 @@ public abstract class AbstractMultiIdEntityLoader implements MultiIdEntityLoa Object[] ids, MultiIdLoadOptions loadOptions, EventSource session) { - if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { - MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef( "#performOrderedMultiLoad(`%s`, ..)", - getLoadable().getEntityName() ); + if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { + MULTI_KEY_LOAD_LOGGER.tracef( "#performOrderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() ); } assert loadOptions.isOrderReturnEnabled(); @@ -87,7 +103,7 @@ public abstract class AbstractMultiIdEntityLoader implements MultiIdEntityLoa final int maxBatchSize = maxBatchSize( ids, loadOptions ); - final List result = CollectionHelper.arrayList( ids.length ); + final List result = arrayList( ids.length ); final List idsInBatch = new ArrayList<>(); final List elementPositionsLoadedByBatch = new ArrayList<>(); @@ -146,7 +162,7 @@ public abstract class AbstractMultiIdEntityLoader implements MultiIdEntityLoa getLoadable().getJavaType().getJavaTypeClass().getName(), lockOptions, session, - LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) + getReadOnlyFromLoadQueryInfluencers( session ) ); Object managedEntity = null; 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 e5c10d1ff4..cd8b428bf6 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 @@ -10,13 +10,11 @@ import java.util.List; import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.engine.internal.BatchFetchQueueHelper; -import org.hibernate.engine.spi.BatchFetchQueue; +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; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.LoadEvent; 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.JdbcMapping; 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.select.SelectStatement; 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.JdbcParameterBindings; 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.spi.ManagedResultConsumer; @@ -43,8 +43,15 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.hibernate.type.descriptor.java.JavaType; 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.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 @@ -52,13 +59,13 @@ import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFrom public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoader implements SqlArrayMultiKeyLoader { private final JdbcMapping arrayJdbcMapping; 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 ); - this.idJdbcTypeCount = identifierColumnSpan; final Class arrayClass = createTypedArray( 0 ).getClass(); - arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( + arrayJdbcMapping = resolveArrayJdbcMapping( getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ), getIdentifierMapping().getJdbcMapping(), arrayClass, @@ -83,7 +90,7 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade // the element value at this position in the result List should be // the EntityKey for that entity - reuse it final EntityKey entityKey = (EntityKey) result.get( position ); - BatchFetchQueueHelper.removeBatchLoadableEntityKey( entityKey, session ); + removeBatchLoadableEntityKey( entityKey, session ); Object entity = persistenceContext.getEntity( entityKey ); if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) { // make sure it is not DELETED @@ -102,28 +109,20 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade @Override protected int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions) { - if ( loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0 ) { - return loadOptions.getBatchSize(); - } - else { - // disable batching by default - return ids.length; -// return getSessionFactory().getJdbcServices().getJdbcEnvironment().getDialect() -// .getBatchLoadSizingStrategy().determineOptimalBatchLoadSize( -// idJdbcTypeCount, -// ids.length, -// getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled() -// ); - } + final Integer explicitBatchSize = loadOptions.getBatchSize(); + return explicitBatchSize != null && explicitBatchSize > 0 + ? explicitBatchSize + // disable batching by default + : ids.length; } @Override protected void loadEntitiesById( - List idsToLoadFromDatabase, + List idsInBatch, LockOptions lockOptions, MultiIdLoadOptions loadOptions, EventSource session) { - final SelectStatement sqlAst = LoaderSelectBuilder.createSelectBySingleArrayParameter( + final SelectStatement sqlAst = createSelectBySingleArrayParameter( getLoadable(), getIdentifierMapping(), session.getLoadQueryInfluencers(), @@ -131,42 +130,31 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade jdbcParameter, getSessionFactory() ); - final JdbcOperationQuerySelect jdbcSelectOperation = getSessionFactory().getJdbcServices() - .getJdbcEnvironment() - .getSqlAstTranslatorFactory() - .buildSelectTranslator( getSessionFactory(), sqlAst ) - .translate( JdbcParameterBindings.NO_BINDINGS, QueryOptions.NONE ); final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(1); - jdbcParameterBindings.addBinding( - jdbcParameter, - new JdbcParameterBindingImpl( arrayJdbcMapping, idsToLoadFromDatabase.toArray( createTypedArray(0 ) ) ) - ); + jdbcParameterBindings.addBinding( jdbcParameter, + new JdbcParameterBindingImpl( arrayJdbcMapping, idsInBatch.toArray( createTypedArray(0) ) ) ); - final PersistenceContext persistenceContext = session.getPersistenceContext(); - final BatchFetchQueue batchFetchQueue = persistenceContext.getBatchFetchQueue(); - - final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler( - batchFetchQueue, - sqlAst, - JdbcParametersList.singleton( jdbcParameter ), - jdbcParameterBindings - ); - - session.getJdbcServices().getJdbcSelectExecutor().executeQuery( - jdbcSelectOperation, + getJdbcSelectExecutor().executeQuery( + getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst ) + .translate( NO_BINDINGS, QueryOptions.NONE ), jdbcParameterBindings, - new ExecutionContextWithSubselectFetchHandler( session, - subSelectFetchableKeysHandler, + new ExecutionContextWithSubselectFetchHandler( + session, + createRegistrationHandler( + session.getPersistenceContext().getBatchFetchQueue(), + sqlAst, + JdbcParametersList.singleton( jdbcParameter ), + jdbcParameterBindings + ), TRUE.equals( loadOptions.getReadOnly( session ) ) ), RowTransformerStandardImpl.instance(), null, - idsToLoadFromDatabase.size(), + idsInBatch.size(), ManagedResultConsumer.INSTANCE ); } - @Override protected List performUnorderedMultiLoad( K[] ids, @@ -180,7 +168,7 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade } final List result = CollectionHelper.arrayList( ids.length ); - final LockOptions lockOptions = (loadOptions.getLockOptions() == null) + final LockOptions lockOptions = loadOptions.getLockOptions() == null ? new LockOptions( LockMode.NONE ) : loadOptions.getLockOptions(); @@ -198,7 +186,7 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade return result; } - final SelectStatement sqlAst = LoaderSelectBuilder.createSelectBySingleArrayParameter( + final SelectStatement sqlAst = createSelectBySingleArrayParameter( getLoadable(), getIdentifierMapping(), session.getLoadQueryInfluencers(), @@ -206,13 +194,11 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade jdbcParameter, getSessionFactory() ); - final JdbcOperationQuerySelect jdbcSelectOperation = getSessionFactory().getJdbcServices() - .getJdbcEnvironment() - .getSqlAstTranslatorFactory() - .buildSelectTranslator( getSessionFactory(), sqlAst ) - .translate( JdbcParameterBindings.NO_BINDINGS, QueryOptions.NONE ); + final JdbcOperationQuerySelect jdbcSelectOperation = + getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst ) + .translate( NO_BINDINGS, QueryOptions.NONE ); - final List databaseResults = LoaderHelper.loadByArrayParameter( + final List databaseResults = loadByArrayParameter( idsToLoadFromDatabase, sqlAst, jdbcSelectOperation, @@ -236,7 +222,7 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade continue; } // found or not, remove the key from the batch-fetch queue - BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, getLoadable(), session ); + removeBatchLoadableEntityKey( id, getLoadable(), session ); } return result; @@ -272,7 +258,7 @@ public class MultiIdEntityLoaderArrayParam extends AbstractMultiIdEntityLoade getLoadable().getJavaType().getJavaTypeClass().getName(), lockOptions, session, - LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) + getReadOnlyFromLoadQueryInfluencers( session ) ); Object managedEntity = null; 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 5533a19fc9..b32821bb69 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 @@ -6,11 +6,11 @@ package org.hibernate.loader.ast.internal; import java.lang.reflect.Array; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.engine.spi.BatchFetchQueue; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; 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.LoadEvent; 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.spi.MultiIdLoadOptions; +import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.spi.QueryOptions; -import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.tree.select.SelectStatement; 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.JdbcParametersList; import org.hibernate.sql.results.internal.RowTransformerStandardImpl; import org.hibernate.sql.results.spi.ListResultsConsumer; import org.hibernate.type.descriptor.java.JavaType; -import org.jboss.logging.Logger; import static java.lang.Boolean.TRUE; 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.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 @@ -47,7 +50,6 @@ import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFrom * @author Steve Ebersole */ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader { - private static final Logger log = Logger.getLogger( MultiIdEntityLoaderStandard.class ); private final int idJdbcTypeCount; @@ -57,10 +59,17 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< SessionFactoryImplementor sessionFactory) { super( entityDescriptor, sessionFactory ); this.idJdbcTypeCount = idColumnSpan; - assert idJdbcTypeCount > 0; } + private boolean isInClauseParameterPaddingEnabled() { + return getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled(); + } + + private MultiKeyLoadSizingStrategy getBatchLoadSizingStrategy() { + return getJdbcServices().getJdbcEnvironment().getDialect().getBatchLoadSizingStrategy(); + } + @Override protected void handleResults( MultiIdLoadOptions loadOptions, @@ -90,17 +99,12 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< @Override protected int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions) { - if ( loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0 ) { - return loadOptions.getBatchSize(); - } - else { - return getSessionFactory().getJdbcServices().getJdbcEnvironment().getDialect() - .getBatchLoadSizingStrategy().determineOptimalBatchLoadSize( - idJdbcTypeCount, - ids.length, - getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled() - ); - } + final Integer explicitBatchSize = loadOptions.getBatchSize(); + return explicitBatchSize != null && explicitBatchSize > 0 + ? explicitBatchSize + : getBatchLoadSizingStrategy() + .determineOptimalBatchLoadSize( idJdbcTypeCount, ids.length, + isInClauseParameterPaddingEnabled() ); } @Override @@ -111,7 +115,6 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< EventSource session) { assert idsInBatch != null; assert !idsInBatch.isEmpty(); - listEntitiesById( idsInBatch, lockOptions, loadOptions, session ); } @@ -121,85 +124,84 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< MultiIdLoadOptions loadOptions, EventSource session) { final int numberOfIdsInBatch = idsInBatch.size(); - if ( numberOfIdsInBatch == 1 ) { - return performSingleMultiLoad( idsInBatch.get( 0 ), lockOptions, session ); + return numberOfIdsInBatch == 1 + ? performSingleMultiLoad( idsInBatch.get( 0 ), lockOptions, session ) + : performRegularMultiLoad( idsInBatch, lockOptions, loadOptions, session, numberOfIdsInBatch ); + } + + private List performRegularMultiLoad( + List 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 = - JdbcParametersList.newBuilder( numberOfIdsInBatch * idJdbcTypeCount ); + final JdbcParametersList.Builder jdbcParametersBuilder = + JdbcParametersList.newBuilder( numberOfIdsInBatch * idJdbcTypeCount ); - final SelectStatement sqlAst = LoaderSelectBuilder.createSelect( - getLoadable(), - // null here means to select everything - null, + final SelectStatement sqlAst = createSelect( + getLoadable(), + // null here means to select everything + 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(), - null, - numberOfIdsInBatch, - 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() + jdbcParameters, + session ); } + // 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 performSingleMultiLoad(Object id, LockOptions lockOptions, SharedSessionContractImplementor session) { - //noinspection unchecked + @SuppressWarnings("unchecked") T loaded = (T) getLoadable().getEntityPersister().load( id, null, lockOptions, session ); - return Collections.singletonList( loaded ); + return singletonList( loaded ); } @Override @@ -210,11 +212,11 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< assert !loadOptions.isOrderReturnEnabled(); assert ids != null; - if ( log.isTraceEnabled() ) { - log.tracef( "#performUnorderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() ); + if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { + MULTI_KEY_LOAD_LOGGER.tracef( "#performUnorderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() ); } - final List result = CollectionHelper.arrayList( ids.length ); + final List result = arrayList( ids.length ); final LockOptions lockOptions = loadOptions.getLockOptions() == null ? new LockOptions( LockMode.NONE ) @@ -241,7 +243,7 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< getLoadable().getJavaType().getJavaTypeClass().getName(), lockOptions, session, - LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session ) + getReadOnlyFromLoadQueryInfluencers( session ) ); Object managedEntity = null; @@ -303,27 +305,23 @@ public class MultiIdEntityLoaderStandard extends AbstractMultiIdEntityLoader< maxBatchSize = loadOptions.getBatchSize(); } else { - maxBatchSize = session.getJdbcServices().getJdbcEnvironment().getDialect().getBatchLoadSizingStrategy().determineOptimalBatchLoadSize( + maxBatchSize = getBatchLoadSizingStrategy().determineOptimalBatchLoadSize( getIdentifierMapping().getJdbcTypeCount(), numberOfIdsLeft, - getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled() + isInClauseParameterPaddingEnabled() ); } int idPosition = 0; while ( numberOfIdsLeft > 0 ) { final int batchSize = Math.min( numberOfIdsLeft, maxBatchSize ); - final Object[] idsInBatch = new Object[ batchSize ]; System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize ); - result.addAll( listEntitiesById( asList( idsInBatch ), lockOptions, loadOptions, session ) ); - numberOfIdsLeft = numberOfIdsLeft - batchSize; idPosition += batchSize; } return result; } - } 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 79b6318715..36e28ac231 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 @@ -857,7 +857,7 @@ public abstract class AbstractEntityPersister protected MultiIdEntityLoader buildMultiIdLoader() { final Dialect dialect = factory.getJdbcServices().getDialect(); return getIdentifierType() instanceof BasicType && supportsSqlArrayType( dialect ) - ? new MultiIdEntityLoaderArrayParam<>( this, identifierColumnSpan, factory ) + ? new MultiIdEntityLoaderArrayParam<>( this, factory ) : new MultiIdEntityLoaderStandard<>( this, identifierColumnSpan, factory ); }