From 8916b16d3b77f92481bfe4eea012729c5ac7559a Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Wed, 9 May 2018 12:14:13 +0200 Subject: [PATCH] HHH-12556 Share data structures between similar LoadPlan based EntityLoaders --- .../AbstractLoadPlanBasedEntityLoader.java | 18 +++++ .../loader/entity/plan/EntityLoader.java | 81 ++++++++++++++++--- .../LegacyBatchingEntityLoaderBuilder.java | 31 ++++--- .../internal/AbstractLoadQueryDetails.java | 9 +++ .../BatchingLoadQueryDetailsFactory.java | 17 ++++ .../exec/internal/EntityLoadQueryDetails.java | 22 +++-- 6 files changed, 147 insertions(+), 31 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java index 05d469d367..05a613203b 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java @@ -28,6 +28,7 @@ import org.hibernate.loader.plan.build.spi.LoadPlanBuildingAssociationVisitation import org.hibernate.loader.plan.build.spi.MetamodelDrivenLoadPlanBuilder; import org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader; import org.hibernate.loader.plan.exec.internal.BatchingLoadQueryDetailsFactory; +import org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails; import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters; import org.hibernate.loader.plan.exec.spi.LoadQueryDetails; import org.hibernate.loader.plan.spi.LoadPlan; @@ -87,6 +88,23 @@ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlan ); } + protected AbstractLoadPlanBasedEntityLoader( + OuterJoinLoadable entityPersister, + SessionFactoryImplementor factory, + EntityLoadQueryDetails entityLoaderQueryDetailsTemplate, + Type uniqueKeyType, + QueryBuildingParameters buildingParameters) { + super( factory ); + this.entityPersister = entityPersister; + this.uniqueKeyType = uniqueKeyType; + this.entityName = entityPersister.getEntityName(); + + this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails( + entityLoaderQueryDetailsTemplate, + buildingParameters + ); + } + @Override protected LoadQueryDetails getStaticLoadQuery() { return staticLoadQuery; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/EntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/EntityLoader.java index fccdca4dd3..4447e31ca5 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/EntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/EntityLoader.java @@ -12,11 +12,11 @@ import org.hibernate.MappingException; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; +import org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails; import org.hibernate.loader.plan.exec.query.internal.QueryBuildingParametersImpl; import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters; import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.type.Type; - import org.jboss.logging.Logger; /** @@ -44,6 +44,7 @@ public class EntityLoader extends AbstractLoadPlanBasedEntityLoader { public static class Builder { private final OuterJoinLoadable persister; + private EntityLoader entityLoaderTemplate; private int batchSize = 1; private LoadQueryInfluencers influencers = LoadQueryInfluencers.NONE; private LockMode lockMode = LockMode.NONE; @@ -53,6 +54,11 @@ public class EntityLoader extends AbstractLoadPlanBasedEntityLoader { this.persister = persister; } + public Builder withEntityLoaderTemplate(EntityLoader entityLoaderTemplate) { + this.entityLoaderTemplate = entityLoaderTemplate; + return this; + } + public Builder withBatchSize(int batchSize) { this.batchSize = batchSize; return this; @@ -79,18 +85,34 @@ public class EntityLoader extends AbstractLoadPlanBasedEntityLoader { public EntityLoader byUniqueKey(String[] keyColumnNames, Type keyType) { // capture current values in a new instance of QueryBuildingParametersImpl - return new EntityLoader( - persister.getFactory(), - persister, - keyColumnNames, - keyType, - new QueryBuildingParametersImpl( - influencers, - batchSize, - lockMode, - lockOptions - ) - ); + if ( entityLoaderTemplate == null ) { + return new EntityLoader( + persister.getFactory(), + persister, + keyColumnNames, + keyType, + new QueryBuildingParametersImpl( + influencers, + batchSize, + lockMode, + lockOptions + ) + ); + } + else { + return new EntityLoader( + persister.getFactory(), + persister, + entityLoaderTemplate, + keyType, + new QueryBuildingParametersImpl( + influencers, + batchSize, + lockMode, + lockOptions + ) + ); + } } } @@ -121,4 +143,37 @@ public class EntityLoader extends AbstractLoadPlanBasedEntityLoader { } } } + + private EntityLoader( + SessionFactoryImplementor factory, + OuterJoinLoadable persister, + EntityLoader entityLoaderTemplate, + Type uniqueKeyType, + QueryBuildingParameters buildingParameters) throws MappingException { + super( persister, factory, entityLoaderTemplate.getStaticLoadQuery(), uniqueKeyType, buildingParameters ); + if ( log.isDebugEnabled() ) { + if ( buildingParameters.getLockOptions() != null ) { + log.debugf( + "Static select for entity %s [%s:%s]: %s", + getEntityName(), + buildingParameters.getLockOptions().getLockMode(), + buildingParameters.getLockOptions().getTimeOut(), + getStaticLoadQuery().getSqlStatement() + ); + } + else if ( buildingParameters.getLockMode() != null ) { + log.debugf( + "Static select for entity %s [%s]: %s", + getEntityName(), + buildingParameters.getLockMode(), + getStaticLoadQuery().getSqlStatement() + ); + } + } + } + + @Override + protected EntityLoadQueryDetails getStaticLoadQuery() { + return (EntityLoadQueryDetails) super.getStaticLoadQuery(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/LegacyBatchingEntityLoaderBuilder.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/LegacyBatchingEntityLoaderBuilder.java index 13e587169d..d8cf9850d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/LegacyBatchingEntityLoaderBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/LegacyBatchingEntityLoaderBuilder.java @@ -20,7 +20,7 @@ import org.hibernate.loader.entity.UniqueEntityLoader; import org.hibernate.persister.entity.OuterJoinLoadable; /** - * LoadPlan-based implementation of the the legacy batch loading strategy + * LoadPlan-based implementation of the legacy batch loading strategy * * @author Steve Ebersole */ @@ -57,15 +57,7 @@ public class LegacyBatchingEntityLoaderBuilder extends AbstractBatchingEntityLoa LockMode lockMode, SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) { - super( persister ); - this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize ); - this.loaders = new EntityLoader[ batchSizes.length ]; - final EntityLoader.Builder entityLoaderBuilder = EntityLoader.forEntity( persister ) - .withInfluencers( loadQueryInfluencers ) - .withLockMode( lockMode ); - for ( int i = 0; i < batchSizes.length; i++ ) { - this.loaders[i] = entityLoaderBuilder.withBatchSize( batchSizes[i] ).byPrimaryKey(); - } + this( persister, maxBatchSize, lockMode, null, factory, loadQueryInfluencers ); } public LegacyBatchingEntityLoader( @@ -74,14 +66,29 @@ public class LegacyBatchingEntityLoaderBuilder extends AbstractBatchingEntityLoa LockOptions lockOptions, SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) { + this( persister, maxBatchSize, null, lockOptions, factory, loadQueryInfluencers ); + } + + protected LegacyBatchingEntityLoader( + OuterJoinLoadable persister, + int maxBatchSize, + LockMode lockMode, + LockOptions lockOptions, + SessionFactoryImplementor factory, + LoadQueryInfluencers loadQueryInfluencers) { super( persister ); this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize ); this.loaders = new EntityLoader[ batchSizes.length ]; final EntityLoader.Builder entityLoaderBuilder = EntityLoader.forEntity( persister ) .withInfluencers( loadQueryInfluencers ) + .withLockMode( lockMode ) .withLockOptions( lockOptions ); - for ( int i = 0; i < batchSizes.length; i++ ) { - this.loaders[i] = entityLoaderBuilder.withBatchSize( batchSizes[i] ).byPrimaryKey(); + + // we create a first entity loader to use it as a template for the others + this.loaders[0] = entityLoaderBuilder.withBatchSize( batchSizes[0] ).byPrimaryKey(); + + for ( int i = 1; i < batchSizes.length; i++ ) { + this.loaders[i] = entityLoaderBuilder.withEntityLoaderTemplate( this.loaders[0] ).withBatchSize( batchSizes[i] ).byPrimaryKey(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java index 07fdd2421c..ee0e648208 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadQueryDetails.java @@ -90,6 +90,15 @@ public abstract class AbstractLoadQueryDetails implements LoadQueryDetails { protected final SessionFactoryImplementor getSessionFactory() { return queryProcessor.getSessionFactory(); } + + protected LoadPlan getLoadPlan() { + return loadPlan; + } + + protected String[] getKeyColumnNames() { + return keyColumnNames; + } + /** * Main entry point for properly handling the FROM clause and and joins and restrictions * diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/BatchingLoadQueryDetailsFactory.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/BatchingLoadQueryDetailsFactory.java index 7f5a1b4a26..6803b70997 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/BatchingLoadQueryDetailsFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/BatchingLoadQueryDetailsFactory.java @@ -68,6 +68,23 @@ public class BatchingLoadQueryDetailsFactory { ); } + /** + * Returns a EntityLoadQueryDetails object based on an existing one and additional elements specific to this one. + * + * @param entityLoadQueryDetailsTemplate the template + * @param buildingParameters And influencers that would affect the generated SQL (mostly we are concerned with those + * that add additional joins here) + * @return The EntityLoadQueryDetails + */ + public LoadQueryDetails makeEntityLoadQueryDetails( + EntityLoadQueryDetails entityLoadQueryDetailsTemplate, + QueryBuildingParameters buildingParameters) { + return new EntityLoadQueryDetails( + entityLoadQueryDetailsTemplate, + buildingParameters + ); + } + /** * Constructs a BasicCollectionLoadQueryDetails object from the given inputs. * diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java index 4dc4a8c6bd..1abf779335 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/EntityLoadQueryDetails.java @@ -10,8 +10,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; -import org.hibernate.LockOptions; -import org.hibernate.Session; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -20,7 +18,6 @@ import org.hibernate.loader.plan.exec.process.internal.AbstractRowReader; import org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl; import org.hibernate.loader.plan.exec.process.internal.EntityReturnReader; import org.hibernate.loader.plan.exec.process.internal.ResultSetProcessingContextImpl; -import org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorHelper; import org.hibernate.loader.plan.exec.process.spi.EntityReferenceInitializer; import org.hibernate.loader.plan.exec.process.spi.ReaderCollector; import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessingContext; @@ -31,12 +28,9 @@ import org.hibernate.loader.plan.exec.spi.EntityReferenceAliases; import org.hibernate.loader.plan.spi.EntityReturn; import org.hibernate.loader.plan.spi.LoadPlan; import org.hibernate.loader.plan.spi.QuerySpace; -import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.Queryable; -import org.hibernate.type.CompositeType; -import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -90,6 +84,22 @@ public class EntityLoadQueryDetails extends AbstractLoadQueryDetails { generate(); } + protected EntityLoadQueryDetails( + EntityLoadQueryDetails initialEntityLoadQueryDetails, + QueryBuildingParameters buildingParameters) { + super( + initialEntityLoadQueryDetails.getLoadPlan(), + (AliasResolutionContextImpl) initialEntityLoadQueryDetails.getAliasResolutionContext(), + buildingParameters, + initialEntityLoadQueryDetails.getKeyColumnNames(), + initialEntityLoadQueryDetails.getRootReturn(), + initialEntityLoadQueryDetails.getSessionFactory() + ); + this.entityReferenceAliases = initialEntityLoadQueryDetails.entityReferenceAliases; + this.readerCollector = initialEntityLoadQueryDetails.readerCollector; + generate(); + } + private EntityReturn getRootEntityReturn() { return (EntityReturn) getRootReturn(); }