cache the @NaturalId loaders

and clean up some of the other loader caching code
This commit is contained in:
Gavin King 2021-02-23 22:57:10 +01:00 committed by Steve Ebersole
parent e0ee9f5b0a
commit 3a24c700fc
1 changed files with 107 additions and 53 deletions

View File

@ -257,6 +257,7 @@ public abstract class AbstractEntityPersister
private final EntityLoaderLazyCollection loaders = new EntityLoaderLazyCollection(); private final EntityLoaderLazyCollection loaders = new EntityLoaderLazyCollection();
private volatile Map<String,EntityLoader> uniqueKeyLoaders; private volatile Map<String,EntityLoader> uniqueKeyLoaders;
private volatile Map<LockMode,EntityLoader> naturalIdLoaders;
// SQL strings // SQL strings
private String sqlVersionSelectString; private String sqlVersionSelectString;
@ -2478,40 +2479,56 @@ public abstract class AbstractEntityPersister
String propertyName, String propertyName,
Object uniqueKey, Object uniqueKey,
SharedSessionContractImplementor session) throws HibernateException { SharedSessionContractImplementor session) throws HibernateException {
return getAppropriateUniqueKeyLoader( propertyName, session ).loadByUniqueKey( session, uniqueKey ); return getAppropriateUniqueKeyLoader( propertyName, session )
.loadByUniqueKey( session, uniqueKey );
} }
public Object loadByNaturalId( public Object loadByNaturalId(
Object[] naturalIdValues, Object[] naturalIdValues,
LockOptions lockOptions, LockOptions lockOptions,
SharedSessionContractImplementor session) throws HibernateException { SharedSessionContractImplementor session) throws HibernateException {
//TODO: cache this return getAppropriateNaturalIdLoader( determineValueNullness( naturalIdValues ), lockOptions, session )
return new EntityLoader( .loadByUniqueKey( session, naturalIdValues );
this,
determineValueNullness( naturalIdValues ),
1,
lockOptions,
getFactory(),
session.getLoadQueryInfluencers()
).loadByUniqueKey( session, naturalIdValues );
} }
private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, SharedSessionContractImplementor session) { private EntityLoader getAppropriateNaturalIdLoader(
final boolean useStaticLoader = !session.getLoadQueryInfluencers().hasEnabledFilters() boolean[] valueNullness,
&& !session.getLoadQueryInfluencers().hasEnabledFetchProfiles() LockOptions lockOptions,
&& propertyName.indexOf( '.' ) < 0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties SharedSessionContractImplementor session) {
LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
return useStaticNaturalIdLoader( valueNullness, lockOptions, loadQueryInfluencers )
? naturalIdLoaders.get( lockOptions.getLockMode() ) :
createNaturalIdLoader( valueNullness, lockOptions, loadQueryInfluencers );
}
if ( useStaticLoader ) { private boolean useStaticNaturalIdLoader(
final Map<String, EntityLoader> uniqueKeyLoaders = this.uniqueKeyLoaders; boolean[] valueNullness,
return uniqueKeyLoaders == null ? null : uniqueKeyLoaders.get( propertyName ); LockOptions lockOptions,
} LoadQueryInfluencers loadQueryInfluencers) {
else { return lockOptions.getTimeOut() == LockOptions.WAIT_FOREVER
return createUniqueKeyLoader( && ArrayHelper.isAllFalse( valueNullness )
propertyMapping.toType( propertyName ), && !loadQueryInfluencers.hasEnabledFilters()
propertyMapping.toColumns( propertyName ), && !loadQueryInfluencers.hasEnabledFetchProfiles();
session.getLoadQueryInfluencers() }
);
} private EntityLoader getAppropriateUniqueKeyLoader(
String propertyName,
SharedSessionContractImplementor session) {
LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
return useStaticUniqueKeyLoader( propertyName, loadQueryInfluencers )
? uniqueKeyLoaders.get( propertyName )
: createUniqueKeyLoader(
propertyMapping.toType( propertyName ),
propertyMapping.toColumns( propertyName ),
loadQueryInfluencers
);
}
private boolean useStaticUniqueKeyLoader(String propertyName, LoadQueryInfluencers loadQueryInfluencers) {
return !loadQueryInfluencers.hasEnabledFilters()
&& !loadQueryInfluencers.hasEnabledFetchProfiles()
//ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
&& propertyName.indexOf( '.' ) < 0;
} }
public int getPropertyIndex(String propertyName) { public int getPropertyIndex(String propertyName) {
@ -2521,10 +2538,10 @@ public abstract class AbstractEntityPersister
protected void createUniqueKeyLoaders() throws MappingException { protected void createUniqueKeyLoaders() throws MappingException {
Type[] propertyTypes = getPropertyTypes(); Type[] propertyTypes = getPropertyTypes();
String[] propertyNames = getPropertyNames(); String[] propertyNames = getPropertyNames();
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) { for ( int i = 0; i < propertyUniqueness.length; i++ ) {
if ( propertyUniqueness[i] ) { if ( propertyUniqueness[i] ) {
if ( uniqueKeyLoaders == null ) { if ( uniqueKeyLoaders == null ) {
this.uniqueKeyLoaders = new HashMap<>(); uniqueKeyLoaders = new HashMap<>();
} }
//don't need filters for the static loaders //don't need filters for the static loaders
uniqueKeyLoaders.put( uniqueKeyLoaders.put(
@ -2538,6 +2555,9 @@ public abstract class AbstractEntityPersister
//TODO: create uk loaders for component properties //TODO: create uk loaders for component properties
} }
} }
if ( uniqueKeyLoaders == null ) {
uniqueKeyLoaders = Collections.emptyMap();
}
} }
private EntityLoader createUniqueKeyLoader( private EntityLoader createUniqueKeyLoader(
@ -2559,6 +2579,40 @@ public abstract class AbstractEntityPersister
); );
} }
protected void createNaturalIdLoaders() throws MappingException {
if ( hasNaturalIdentifier() ) {
naturalIdLoaders = new HashMap<>();
boolean[] valueNullness = new boolean[ getNaturalIdentifierProperties().length ];
for ( LockMode lockMode : LockMode.values() ) {
naturalIdLoaders.put(
lockMode,
createNaturalIdLoader(
valueNullness,
new LockOptions(lockMode),
LoadQueryInfluencers.NONE
)
);
}
}
else {
naturalIdLoaders = Collections.emptyMap();
}
}
private EntityLoader createNaturalIdLoader(
boolean[] valueNullness,
LockOptions lockOptions,
LoadQueryInfluencers loadQueryInfluencers) {
return new EntityLoader(
this,
valueNullness,
1,
lockOptions,
getFactory(),
loadQueryInfluencers
);
}
protected String getSQLWhereString(String alias) { protected String getSQLWhereString(String alias) {
return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias ); return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
} }
@ -4356,6 +4410,7 @@ public abstract class AbstractEntityPersister
createLoaders(); createLoaders();
createUniqueKeyLoaders(); createUniqueKeyLoaders();
createNaturalIdLoaders();
createQueryLoader(); createQueryLoader();
doPostInstantiate(); doPostInstantiate();
@ -4570,33 +4625,32 @@ public abstract class AbstractEntityPersister
// regardless of any other consideration // regardless of any other consideration
return queryLoader; return queryLoader;
} }
else if ( isAffectedByEnabledFilters( session ) ) {
// because filters affect the rows returned (because they add
// restrictions) these need to be next in precedence
return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() );
}
else if ( session.getLoadQueryInfluencers().getInternalFetchProfile() != null && LockMode.UPGRADE.greaterThan(
lockOptions.getLockMode()
) ) {
// Next, we consider whether an 'internal' fetch profile has been set.
// This indicates a special fetch profile Hibernate needs applied
// (for its merge loading process e.g.).
final String internalFetchProfile = session.getLoadQueryInfluencers().getInternalFetchProfile();
return getLoaderByString( internalFetchProfile );
}
else if ( isAffectedByEnabledFetchProfiles( session ) ) {
// If the session has associated influencers we need to adjust the
// SQL query used for loading based on those influencers
return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() );
}
else if ( isAffectedByEntityGraph( session ) ) {
return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() );
}
else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) {
return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() );
}
else { else {
return getLoaderByLockMode( lockOptions.getLockMode() ); LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
if ( isAffectedByEnabledFilters( session ) ) {
// because filters affect the rows returned (because they add
// restrictions) these need to be next in precedence
return createEntityLoader( lockOptions, loadQueryInfluencers );
}
else if ( loadQueryInfluencers.getInternalFetchProfile() != null
&& LockMode.UPGRADE.greaterThan( lockOptions.getLockMode() ) ) {
// Next, we consider whether an 'internal' fetch profile has been set.
// This indicates a special fetch profile Hibernate needs applied
// (for its merge loading process e.g.).
return getLoaderByString( loadQueryInfluencers.getInternalFetchProfile() );
}
else if ( isAffectedByEnabledFetchProfiles( session )
|| isAffectedByEntityGraph( session ) ) {
// If the session has associated influencers we need to adjust the
// SQL query used for loading based on those influencers
return createEntityLoader( lockOptions, loadQueryInfluencers );
}
else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) {
return createEntityLoader( lockOptions, loadQueryInfluencers );
}
else {
return getLoaderByLockMode( lockOptions.getLockMode() );
}
} }
} }