HHH-12556 Share data structures between similar LoadPlan based EntityLoaders

This commit is contained in:
Guillaume Smet 2018-05-09 12:14:13 +02:00
parent fcd9467aa3
commit 8916b16d3b
6 changed files with 147 additions and 31 deletions

View File

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

View File

@ -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,6 +85,7 @@ public class EntityLoader extends AbstractLoadPlanBasedEntityLoader {
public EntityLoader byUniqueKey(String[] keyColumnNames, Type keyType) {
// capture current values in a new instance of QueryBuildingParametersImpl
if ( entityLoaderTemplate == null ) {
return new EntityLoader(
persister.getFactory(),
persister,
@ -92,6 +99,21 @@ public class EntityLoader extends AbstractLoadPlanBasedEntityLoader {
)
);
}
else {
return new EntityLoader(
persister.getFactory(),
persister,
entityLoaderTemplate,
keyType,
new QueryBuildingParametersImpl(
influencers,
batchSize,
lockMode,
lockOptions
)
);
}
}
}
private EntityLoader(
@ -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();
}
}

View File

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

View File

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

View File

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

View File

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