lay foundation for making batch/subselect fetching per-session
still need to fix caching of loaders in persisters
This commit is contained in:
parent
ed213d7cdf
commit
e102dea3be
|
@ -145,4 +145,8 @@ public interface SessionBuilder {
|
|||
* @see jakarta.persistence.PersistenceContextType
|
||||
*/
|
||||
SessionBuilder autoClose(boolean autoClose);
|
||||
|
||||
SessionBuilder defaultBatchFetchSize(int batchSize);
|
||||
|
||||
SessionBuilder subselectFetchEnabled(boolean enabled);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,10 @@ public interface SharedSessionBuilder extends SessionBuilder {
|
|||
*/
|
||||
SharedSessionBuilder flushMode();
|
||||
|
||||
SharedSessionBuilder defaultBatchFetchSize();
|
||||
|
||||
SharedSessionBuilder subselectFetchEnabled();
|
||||
|
||||
/**
|
||||
* Signifies that the autoClose flag from the original session should be used to create the new session.
|
||||
*
|
||||
|
@ -84,4 +88,10 @@ public interface SharedSessionBuilder extends SessionBuilder {
|
|||
|
||||
@Override
|
||||
SharedSessionBuilder autoClose(boolean autoClose);
|
||||
|
||||
@Override
|
||||
SharedSessionBuilder defaultBatchFetchSize(int batchSize);
|
||||
|
||||
@Override
|
||||
SharedSessionBuilder subselectFetchEnabled(boolean enabled);
|
||||
}
|
||||
|
|
|
@ -1029,8 +1029,8 @@ public interface AvailableSettings {
|
|||
* a value greater than one, Hibernate will use batch fetching, when
|
||||
* possible, to fetch any association.
|
||||
* <p>
|
||||
* By default, Hibernate only uses batch fetching for associations
|
||||
* explicitly annotated {@code @BatchSize}.
|
||||
* By default, Hibernate only uses batch fetching for entities and
|
||||
* collections explicitly annotated {@code @BatchSize}.
|
||||
*
|
||||
* @see org.hibernate.annotations.BatchSize
|
||||
* @see org.hibernate.boot.SessionFactoryBuilder#applyDefaultBatchFetchSize(int)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.engine.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -21,6 +20,8 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
|
@ -30,7 +31,7 @@ public class BatchFetchQueueHelper {
|
|||
BatchFetchQueueHelper.class.getName()
|
||||
);
|
||||
|
||||
private BatchFetchQueueHelper(){
|
||||
private BatchFetchQueueHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,23 +48,20 @@ public class BatchFetchQueueHelper {
|
|||
List<?> results,
|
||||
EntityPersister persister,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( !persister.isBatchLoadable() ) {
|
||||
return;
|
||||
}
|
||||
if ( ids.length == results.size() ) {
|
||||
return;
|
||||
}
|
||||
LOG.debug( "Not all entities were loaded." );
|
||||
Set<Serializable> idSet = new HashSet<>( Arrays.asList( ids ) );
|
||||
for ( Object result : results ) {
|
||||
// All results should be in the PersistenceContext
|
||||
idSet.remove( session.getContextEntityIdentifier( result ) );
|
||||
}
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debug( "Entities of type [" + persister.getEntityName() + "] not found; IDs: " + idSet );
|
||||
}
|
||||
for ( Object id : idSet ) {
|
||||
removeBatchLoadableEntityKey( id, persister, session );
|
||||
if ( ids.length != results.size()
|
||||
&& session.getLoadQueryInfluencers().effectivelyBatchLoadable( persister ) ) {
|
||||
LOG.debug( "Not all entities were loaded." );
|
||||
final Set<Serializable> idSet = new HashSet<>( asList( ids ) );
|
||||
for ( Object result : results ) {
|
||||
// All results should be in the PersistenceContext
|
||||
idSet.remove( session.getContextEntityIdentifier( result ) );
|
||||
}
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debug( "Entities of type [" + persister.getEntityName() + "] not found; IDs: " + idSet );
|
||||
}
|
||||
for ( Object id : idSet ) {
|
||||
removeBatchLoadableEntityKey( id, persister, session );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,9 +73,8 @@ public class BatchFetchQueueHelper {
|
|||
Object id,
|
||||
EntityPersister persister,
|
||||
SharedSessionContractImplementor session) {
|
||||
final EntityKey entityKey = session.generateEntityKey( id, persister );
|
||||
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
|
||||
batchFetchQueue.removeBatchLoadableEntityKey( entityKey );
|
||||
session.getPersistenceContextInternal().getBatchFetchQueue()
|
||||
.removeBatchLoadableEntityKey( session.generateEntityKey( id, persister ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,8 +84,7 @@ public class BatchFetchQueueHelper {
|
|||
public static void removeBatchLoadableEntityKey(
|
||||
EntityKey entityKey,
|
||||
SharedSessionContractImplementor session) {
|
||||
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
|
||||
batchFetchQueue.removeBatchLoadableEntityKey( entityKey );
|
||||
session.getPersistenceContextInternal().getBatchFetchQueue().removeBatchLoadableEntityKey( entityKey );
|
||||
}
|
||||
|
||||
public static void removeBatchLoadableEntityKey(
|
||||
|
|
|
@ -868,7 +868,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
public void addUninitializedCollection(CollectionPersister persister, PersistentCollection<?> collection, Object id) {
|
||||
final CollectionEntry ce = new CollectionEntry( collection, persister, id, flushing );
|
||||
addCollection( collection, ce, id );
|
||||
if ( session.getLoadQueryInfluencers().effectiveBatchSize( persister ) > 1 ) {
|
||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( persister ) ) {
|
||||
getBatchFetchQueue().addBatchLoadableCollection( collection, ce );
|
||||
}
|
||||
}
|
||||
|
@ -877,7 +877,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
public void addUninitializedDetachedCollection(CollectionPersister persister, PersistentCollection<?> collection) {
|
||||
final CollectionEntry ce = new CollectionEntry( persister, collection.getKey() );
|
||||
addCollection( collection, ce, collection.getKey() );
|
||||
if ( session.getLoadQueryInfluencers().effectiveBatchSize( persister ) > 1 ) {
|
||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( persister ) ) {
|
||||
getBatchFetchQueue().addBatchLoadableCollection( collection, ce );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ public abstract class AbstractDelegatingSessionBuilder implements SessionBuilder
|
|||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected SessionBuilder getThis() {
|
||||
return this;
|
||||
}
|
||||
|
@ -123,4 +122,16 @@ public abstract class AbstractDelegatingSessionBuilder implements SessionBuilder
|
|||
delegate.flushMode( flushMode );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionBuilder defaultBatchFetchSize(int batchSize) {
|
||||
delegate.defaultBatchFetchSize( batchSize );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionBuilder subselectFetchEnabled(boolean enabled) {
|
||||
delegate.subselectFetchEnabled( enabled );
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ public abstract class AbstractDelegatingSharedSessionBuilder implements SharedSe
|
|||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected SharedSessionBuilder getThis() {
|
||||
return this;
|
||||
}
|
||||
|
@ -165,4 +164,28 @@ public abstract class AbstractDelegatingSharedSessionBuilder implements SharedSe
|
|||
delegate.jdbcTimeZone( timeZone );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilder defaultBatchFetchSize(int batchSize) {
|
||||
delegate.defaultBatchFetchSize( batchSize );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilder subselectFetchEnabled(boolean enabled) {
|
||||
delegate.subselectFetchEnabled( enabled );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilder defaultBatchFetchSize() {
|
||||
delegate.defaultBatchFetchSize();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilder subselectFetchEnabled() {
|
||||
delegate.subselectFetchEnabled();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ public class BatchFetchQueue {
|
|||
* already associated with the {@link PersistenceContext}.
|
||||
*/
|
||||
public void addBatchLoadableEntityKey(EntityKey key) {
|
||||
if ( key.isBatchLoadable() ) {
|
||||
if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) {
|
||||
if ( batchLoadableEntityKeys == null ) {
|
||||
batchLoadableEntityKeys = CollectionHelper.mapOfSize( 12 );
|
||||
}
|
||||
|
@ -165,10 +165,11 @@ public class BatchFetchQueue {
|
|||
* if necessary
|
||||
*/
|
||||
public void removeBatchLoadableEntityKey(EntityKey key) {
|
||||
if ( batchLoadableEntityKeys != null && key.isBatchLoadable() ) {
|
||||
LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
|
||||
if ( batchLoadableEntityKeys != null
|
||||
&& key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) {
|
||||
final LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
|
||||
if ( set != null ) {
|
||||
set.remove(key);
|
||||
set.remove( key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +178,8 @@ public class BatchFetchQueue {
|
|||
* Intended for test usage. Really has no use-case in Hibernate proper.
|
||||
*/
|
||||
public boolean containsEntityKey(EntityKey key) {
|
||||
if ( batchLoadableEntityKeys != null && key.isBatchLoadable() ) {
|
||||
if ( batchLoadableEntityKeys != null
|
||||
&& key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) {
|
||||
LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
|
||||
if ( set != null ) {
|
||||
return set.contains( key );
|
||||
|
@ -523,4 +525,7 @@ public class BatchFetchQueue {
|
|||
return false;
|
||||
}
|
||||
|
||||
public SharedSessionContractImplementor getSession() {
|
||||
return context.getSession();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ public final class CollectionEntry implements Serializable {
|
|||
: null;
|
||||
collection.setSnapshot( loadedKey, role, snapshot );
|
||||
final SharedSessionContractImplementor session = ((AbstractPersistentCollection<?>) collection).getSession();
|
||||
if ( session.getLoadQueryInfluencers().effectiveBatchSize( loadedPersister ) > 1 ) {
|
||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( loadedPersister ) ) {
|
||||
session.getPersistenceContextInternal()
|
||||
.getBatchFetchQueue()
|
||||
.removeBatchLoadableCollection( this );
|
||||
|
|
|
@ -61,8 +61,8 @@ public final class EntityKey implements Serializable {
|
|||
return result;
|
||||
}
|
||||
|
||||
public boolean isBatchLoadable() {
|
||||
return persister.isBatchLoadable();
|
||||
public boolean isBatchLoadable(LoadQueryInfluencers influencers) {
|
||||
return influencers.effectivelyBatchLoadable( persister );
|
||||
}
|
||||
|
||||
public Object getIdentifierValue() {
|
||||
|
|
|
@ -18,8 +18,10 @@ import java.util.function.Supplier;
|
|||
import org.hibernate.Filter;
|
||||
import org.hibernate.UnknownProfileException;
|
||||
import org.hibernate.internal.FilterImpl;
|
||||
import org.hibernate.internal.SessionCreationOptions;
|
||||
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
* Centralize all options which can influence the SQL query needed to load an
|
||||
|
@ -36,7 +38,10 @@ public class LoadQueryInfluencers implements Serializable {
|
|||
* Static reference useful for cases where we are creating load SQL
|
||||
* outside the context of any influencers. One such example is
|
||||
* anything created by the session factory.
|
||||
*
|
||||
* @deprecated use {@link #LoadQueryInfluencers(SessionFactoryImplementor)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public static final LoadQueryInfluencers NONE = new LoadQueryInfluencers();
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
@ -49,25 +54,28 @@ public class LoadQueryInfluencers implements Serializable {
|
|||
//Lazily initialized!
|
||||
private HashMap<String,Filter> enabledFilters;
|
||||
|
||||
private Boolean subselectFetchEnabled;
|
||||
private boolean subselectFetchEnabled;
|
||||
|
||||
private Integer batchSize;
|
||||
private int batchSize = -1;
|
||||
|
||||
private final EffectiveEntityGraph effectiveEntityGraph = new EffectiveEntityGraph();
|
||||
|
||||
private Boolean readOnly;
|
||||
|
||||
public LoadQueryInfluencers() {
|
||||
this( null, null );
|
||||
this.sessionFactory = null;
|
||||
}
|
||||
|
||||
public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory) {
|
||||
this( sessionFactory, null );
|
||||
this.sessionFactory = sessionFactory;
|
||||
batchSize = sessionFactory.getSessionFactoryOptions().getDefaultBatchFetchSize();
|
||||
subselectFetchEnabled = sessionFactory.getSessionFactoryOptions().isSubselectFetchEnabled();
|
||||
}
|
||||
|
||||
public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory, Boolean readOnly) {
|
||||
public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory, SessionCreationOptions options) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.readOnly = readOnly;
|
||||
batchSize = options.getDefaultBatchFetchSize();
|
||||
subselectFetchEnabled = options.isSubselectFetchEnabled();
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
|
@ -255,28 +263,46 @@ public class LoadQueryInfluencers implements Serializable {
|
|||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public Integer getBatchSize() {
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public void setBatchSize(Integer batchSize) {
|
||||
public void setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
public int effectiveBatchSize(CollectionPersister persister) {
|
||||
return batchSize != null ? batchSize : persister.getBatchSize();
|
||||
int persisterBatchSize = persister.getBatchSize();
|
||||
// persister-specific batch size overrides global setting
|
||||
// (note that due to legacy, -1 means no explicit setting)
|
||||
return persisterBatchSize >= 0 ? persisterBatchSize : batchSize;
|
||||
}
|
||||
|
||||
public Boolean getSubselectFetchEnabled() {
|
||||
public boolean effectivelyBatchLoadable(CollectionPersister persister) {
|
||||
return batchSize > 1 || persister.isBatchLoadable();
|
||||
}
|
||||
|
||||
public int effectiveBatchSize(EntityPersister persister) {
|
||||
int persisterBatchSize = persister.getBatchSize();
|
||||
// persister-specific batch size overrides global setting
|
||||
// (note that due to legacy, -1 means no explicit setting)
|
||||
return persisterBatchSize >= 0 ? persisterBatchSize : batchSize;
|
||||
}
|
||||
|
||||
public boolean effectivelyBatchLoadable(EntityPersister persister) {
|
||||
return batchSize > 1 || persister.isBatchLoadable();
|
||||
}
|
||||
|
||||
public boolean getSubselectFetchEnabled() {
|
||||
return subselectFetchEnabled;
|
||||
}
|
||||
|
||||
public void setSubselectFetchEnabled(Boolean subselectFetchEnabled) {
|
||||
public void setSubselectFetchEnabled(boolean subselectFetchEnabled) {
|
||||
this.subselectFetchEnabled = subselectFetchEnabled;
|
||||
}
|
||||
|
||||
public boolean effectiveSubselectFetchEnabled(CollectionPersister persister) {
|
||||
return subselectFetchEnabled != null ? subselectFetchEnabled : persister.isSubselectLoadable();
|
||||
return subselectFetchEnabled || persister.isSubselectLoadable();
|
||||
}
|
||||
|
||||
private void checkMutability() {
|
||||
|
@ -286,4 +312,9 @@ public class LoadQueryInfluencers implements Serializable {
|
|||
throw new IllegalStateException( "Cannot modify context-less LoadQueryInfluencers" );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSubselectLoadableCollections(EntityPersister persister) {
|
||||
return persister.hasSubselectLoadableCollections()
|
||||
|| subselectFetchEnabled && persister.hasCollections();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,13 +150,9 @@ public class SubselectFetch {
|
|||
}
|
||||
|
||||
public void addKey(EntityKey key, LoadingEntityEntry entry) {
|
||||
|
||||
final EntityPersister persister = entry.getDescriptor();
|
||||
boolean subselectsPossible =
|
||||
persister.hasCollections()
|
||||
&& persister.getFactory().getSessionFactoryOptions().isSubselectFetchEnabled()
|
||||
|| persister.hasSubselectLoadableCollections();
|
||||
if ( subselectsPossible && shouldAddSubselectFetch( entry ) ) {
|
||||
if ( batchFetchQueue.getSession().getLoadQueryInfluencers()
|
||||
.hasSubselectLoadableCollections( entry.getDescriptor() )
|
||||
&& shouldAddSubselectFetch( entry ) ) {
|
||||
final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent(
|
||||
entry.getEntityInitializer().getNavigablePath(),
|
||||
navigablePath -> new SubselectFetch(
|
||||
|
@ -178,17 +174,18 @@ public class SubselectFetch {
|
|||
if ( entry.getEntityInitializer() instanceof EntityResultInitializer ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
final NavigablePath entityInitializerParent = entry.getEntityInitializer().getNavigablePath().getParent();
|
||||
|
||||
final NavigablePath entityInitializerParent = entry.getEntityInitializer().getNavigablePath().getParent();
|
||||
|
||||
// We want to add only the collections of the loading entities
|
||||
for ( DomainResult<?> domainResult : loadingSqlAst.getDomainResultDescriptors() ) {
|
||||
if ( domainResult.getNavigablePath().equals( entityInitializerParent ) ) {
|
||||
return true;
|
||||
// We want to add only the collections of the loading entities
|
||||
for ( DomainResult<?> domainResult : loadingSqlAst.getDomainResultDescriptors() ) {
|
||||
if ( domainResult.getNavigablePath().equals( entityInitializerParent ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
|||
EntityPersister persister,
|
||||
EntityKey keyToLoad,
|
||||
EventSource session) {
|
||||
if ( keyToLoad.isBatchLoadable() ) {
|
||||
if ( keyToLoad.isBatchLoadable( session.getLoadQueryInfluencers() ) ) {
|
||||
// Add a batch-fetch entry into the queue for this entity
|
||||
session.getPersistenceContextInternal().getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
|
||||
}
|
||||
|
@ -565,10 +565,9 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
|||
}
|
||||
|
||||
private Object load(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) {
|
||||
final EventSource session = event.getSession();
|
||||
final Object entity = loadFromCacheOrDatasource( event, persister, keyToLoad );
|
||||
if ( entity != null && persister.hasNaturalIdentifier() ) {
|
||||
session.getPersistenceContextInternal().getNaturalIdResolutions()
|
||||
event.getSession().getPersistenceContextInternal().getNaturalIdResolutions()
|
||||
.cacheResolutionFromLoad(
|
||||
event.getEntityId(),
|
||||
persister.getNaturalIdMapping().extractNaturalIdFromEntity( entity ),
|
||||
|
@ -579,13 +578,12 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
|||
}
|
||||
|
||||
private Object loadFromCacheOrDatasource(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) {
|
||||
final EventSource session = event.getSession();
|
||||
final Object entity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( event, persister, keyToLoad );
|
||||
if ( entity != null ) {
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev(
|
||||
"Resolved object in second-level cache: {0}",
|
||||
infoString( persister, event.getEntityId(), session.getFactory() )
|
||||
infoString( persister, event.getEntityId(), event.getSession().getFactory() )
|
||||
);
|
||||
}
|
||||
return entity;
|
||||
|
@ -594,7 +592,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
|||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev(
|
||||
"Object not resolved in any cache: {0}",
|
||||
infoString( persister, event.getEntityId(), session.getFactory() )
|
||||
infoString( persister, event.getEntityId(), event.getSession().getFactory() )
|
||||
);
|
||||
}
|
||||
return loadFromDatasource( event, persister );
|
||||
|
|
|
@ -73,21 +73,23 @@ public class EvictVisitor extends AbstractVisitor {
|
|||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
final CollectionEntry ce = persistenceContext.removeCollectionEntry( collection );
|
||||
final CollectionPersister persister = ce.getLoadedPersister();
|
||||
final Object loadedKey = ce.getLoadedKey();
|
||||
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf(
|
||||
"Evicting collection: %s",
|
||||
collectionInfoString( persister, collection, ce.getLoadedKey(), session )
|
||||
collectionInfoString( persister, collection, loadedKey, session )
|
||||
);
|
||||
}
|
||||
|
||||
if ( persister != null
|
||||
&& session.getLoadQueryInfluencers().effectiveBatchSize(persister) > 1 ) {
|
||||
persistenceContext.getBatchFetchQueue().removeBatchLoadableCollection( ce );
|
||||
}
|
||||
if ( persister != null && ce.getLoadedKey() != null ) {
|
||||
//TODO: is this 100% correct?
|
||||
persistenceContext.removeCollectionByKey( new CollectionKey( persister, ce.getLoadedKey() ) );
|
||||
if ( persister != null ) {
|
||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( persister ) ) {
|
||||
persistenceContext.getBatchFetchQueue().removeBatchLoadableCollection( ce );
|
||||
}
|
||||
if ( loadedKey != null ) {
|
||||
//TODO: is this 100% correct?
|
||||
persistenceContext.removeCollectionByKey( new CollectionKey( persister, loadedKey) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,10 @@ public interface SessionCreationOptions {
|
|||
|
||||
FlushMode getInitialSessionFlushMode();
|
||||
|
||||
boolean isSubselectFetchEnabled();
|
||||
|
||||
int getDefaultBatchFetchSize();
|
||||
|
||||
boolean shouldAutoClose();
|
||||
|
||||
boolean shouldAutoClear();
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionBuilder;
|
||||
import org.hibernate.SessionEventListener;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.SessionFactoryObserver;
|
||||
|
@ -1195,6 +1196,8 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
|||
private String tenantIdentifier;
|
||||
private TimeZone jdbcTimeZone;
|
||||
private boolean explicitNoInterceptor;
|
||||
private int defaultBatchFetchSize;
|
||||
private boolean subselectFetchEnabled;
|
||||
|
||||
// Lazy: defaults can be built by invoking the builder in fastSessionServices.defaultSessionEventListeners
|
||||
// (Need a fresh build for each Session as the listener instances can't be reused across sessions)
|
||||
|
@ -1212,6 +1215,8 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
|||
this.statementInspector = sessionFactoryOptions.getStatementInspector();
|
||||
this.connectionHandlingMode = sessionFactoryOptions.getPhysicalConnectionHandlingMode();
|
||||
this.autoClose = sessionFactoryOptions.isAutoCloseSessionEnabled();
|
||||
this.defaultBatchFetchSize = sessionFactoryOptions.getDefaultBatchFetchSize();
|
||||
this.subselectFetchEnabled = sessionFactoryOptions.isSubselectFetchEnabled();
|
||||
|
||||
final CurrentTenantIdentifierResolver currentTenantIdentifierResolver = sessionFactory.getCurrentTenantIdentifierResolver();
|
||||
if ( currentTenantIdentifierResolver != null ) {
|
||||
|
@ -1241,6 +1246,16 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
|||
return flushMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubselectFetchEnabled() {
|
||||
return subselectFetchEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultBatchFetchSize() {
|
||||
return defaultBatchFetchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldAutoClose() {
|
||||
return autoClose;
|
||||
|
@ -1345,6 +1360,18 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionBuilder defaultBatchFetchSize(int batchSize) {
|
||||
defaultBatchFetchSize = batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionBuilder subselectFetchEnabled(boolean enabled) {
|
||||
subselectFetchEnabled = enabled;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionBuilderImpl flushMode(FlushMode flushMode) {
|
||||
this.flushMode = flushMode;
|
||||
|
@ -1428,6 +1455,16 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
|
|||
return FlushMode.ALWAYS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubselectFetchEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultBatchFetchSize() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldAutoClose() {
|
||||
return false;
|
||||
|
|
|
@ -239,7 +239,7 @@ public class SessionImpl
|
|||
}
|
||||
}
|
||||
|
||||
loadQueryInfluencers = new LoadQueryInfluencers( factory );
|
||||
loadQueryInfluencers = new LoadQueryInfluencers( factory, options );
|
||||
|
||||
final StatisticsImplementor statistics = factory.getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
|
@ -1932,6 +1932,7 @@ public class SessionImpl
|
|||
loadQueryInfluencers.disableFetchProfile( name );
|
||||
}
|
||||
|
||||
// TODO: unused for now, should we promote to Session?
|
||||
public void setSubselectFetchingEnabled(boolean enabled) {
|
||||
loadQueryInfluencers.setSubselectFetchEnabled( enabled );
|
||||
}
|
||||
|
@ -1940,6 +1941,7 @@ public class SessionImpl
|
|||
return loadQueryInfluencers.getSubselectFetchEnabled();
|
||||
}
|
||||
|
||||
// TODO: unused for now, should we promote to Session?
|
||||
public void setFetchBatchSize(int batchSize) {
|
||||
loadQueryInfluencers.setBatchSize( batchSize );
|
||||
}
|
||||
|
@ -2147,6 +2149,28 @@ public class SessionImpl
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilderImpl defaultBatchFetchSize(int batchSize) {
|
||||
super.defaultBatchFetchSize( batchSize );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilderImpl subselectFetchEnabled(boolean enabled) {
|
||||
super.subselectFetchEnabled( enabled );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilder defaultBatchFetchSize() {
|
||||
return defaultBatchFetchSize( session.getFetchBatchSize() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilder subselectFetchEnabled() {
|
||||
return subselectFetchEnabled( session.isSubselectFetchingEnabled() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionBuilderImpl autoClose() {
|
||||
autoClose( session.autoClose );
|
||||
|
@ -2911,11 +2935,7 @@ public class SessionImpl
|
|||
}
|
||||
|
||||
private Boolean getReadOnlyFromLoadQueryInfluencers() {
|
||||
Boolean readOnly = null;
|
||||
if ( loadQueryInfluencers != null ) {
|
||||
readOnly = loadQueryInfluencers.getReadOnly();
|
||||
}
|
||||
return readOnly;
|
||||
return loadQueryInfluencers != null ? loadQueryInfluencers.getReadOnly() : null;
|
||||
}
|
||||
|
||||
@Override @Deprecated(forRemoval = true)
|
||||
|
|
|
@ -62,13 +62,13 @@ import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
|
|||
public class StatelessSessionImpl extends AbstractSharedSessionContract implements StatelessSession {
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( StatelessSessionImpl.class );
|
||||
|
||||
private static final LoadQueryInfluencers NO_INFLUENCERS = new LoadQueryInfluencers( null ) {
|
||||
@Override
|
||||
private static final LoadQueryInfluencers NO_INFLUENCERS = new LoadQueryInfluencers() {
|
||||
@Override @Deprecated
|
||||
public String getInternalFetchProfile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @Deprecated
|
||||
public void setInternalFetchProfile(String internalFetchProfile) {
|
||||
}
|
||||
};
|
||||
|
|
|
@ -156,7 +156,7 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
|
|||
lockOptions,
|
||||
fetchProcessor,
|
||||
true,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
sessionFactory
|
||||
);
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ class DatabaseSnapshotExecutor {
|
|||
LockOptions.NONE,
|
||||
(fetchParent, creationState) -> ImmutableFetchList.EMPTY,
|
||||
true,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
sessionFactory
|
||||
);
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ public class EntityBatchLoaderArrayParam<T>
|
|||
sqlAst = LoaderSelectBuilder.createSelectBySingleArrayParameter(
|
||||
getLoadable(),
|
||||
identifierMapping,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
LockOptions.NONE,
|
||||
jdbcParameter,
|
||||
sessionFactory
|
||||
|
|
|
@ -312,7 +312,7 @@ public class EntityBatchLoaderInPredicate<T>
|
|||
identifierMapping,
|
||||
null,
|
||||
sqlBatchSize,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
LockOptions.NONE,
|
||||
jdbcParameters::add,
|
||||
sessionFactory
|
||||
|
|
|
@ -227,9 +227,8 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
|||
getSessionFactory()
|
||||
);
|
||||
|
||||
final JdbcServices jdbcServices = getSessionFactory().getJdbcServices();
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory =
|
||||
getSessionFactory().getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
|
||||
|
||||
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( jdbcParameters.size() );
|
||||
int offset = 0;
|
||||
|
@ -252,10 +251,7 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
|||
.translate( jdbcParameterBindings, QueryOptions.NONE );
|
||||
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
|
||||
final EntityPersister persister = getLoadable().getEntityPersister();
|
||||
if ( persister.hasCollections()
|
||||
&& session.getSessionFactory().getSessionFactoryOptions().isSubselectFetchEnabled()
|
||||
|| persister.hasSubselectLoadableCollections() ) {
|
||||
if ( session.getLoadQueryInfluencers().hasSubselectLoadableCollections( getLoadable().getEntityPersister() ) ) {
|
||||
subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlAst,
|
||||
|
|
|
@ -84,9 +84,8 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
|
||||
this.keyValueResolver = keyValueResolver;
|
||||
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory =
|
||||
sessionFactory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
|
||||
this.jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, sqlSelect )
|
||||
.translate( null, QueryOptions.NONE );
|
||||
}
|
||||
|
@ -139,10 +138,7 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
private <E> List<E> performLoad(JdbcParameterBindings jdbcParamBindings, SharedSessionContractImplementor session) {
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
|
||||
|
||||
final EntityPersister persister = entityDescriptor.getEntityPersister();
|
||||
if ( persister.hasCollections()
|
||||
&& session.getSessionFactory().getSessionFactoryOptions().isSubselectFetchEnabled()
|
||||
|| persister.hasSubselectLoadableCollections() ) {
|
||||
if ( session.getLoadQueryInfluencers().hasSubselectLoadableCollections( entityDescriptor.getEntityPersister() ) ) {
|
||||
subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlSelect,
|
||||
|
|
|
@ -34,6 +34,8 @@ import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
|||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -73,7 +75,7 @@ public class SingleUniqueKeyEntityLoaderStandard<T> implements SingleUniqueKeyEn
|
|||
Collections.emptyList(),
|
||||
uniqueKeyAttribute,
|
||||
null,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
LockOptions.NONE,
|
||||
jdbcParameters::add,
|
||||
sessionFactory
|
||||
|
@ -125,10 +127,10 @@ public class SingleUniqueKeyEntityLoaderStandard<T> implements SingleUniqueKeyEn
|
|||
final List<JdbcParameter> jdbcParameters = new ArrayList<>();
|
||||
final SelectStatement sqlAst = LoaderSelectBuilder.createSelectByUniqueKey(
|
||||
entityDescriptor,
|
||||
Collections.singletonList( entityDescriptor.getIdentifierMapping() ),
|
||||
singletonList( entityDescriptor.getIdentifierMapping() ),
|
||||
uniqueKeyAttribute,
|
||||
null,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
LockOptions.NONE,
|
||||
jdbcParameters::add,
|
||||
sessionFactory
|
||||
|
|
|
@ -69,7 +69,7 @@ public class GeneratedValuesProcessor {
|
|||
entityDescriptor.getIdentifierMapping(),
|
||||
null,
|
||||
1,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( sessionFactory ),
|
||||
LockOptions.READ,
|
||||
jdbcParameters::add,
|
||||
sessionFactory
|
||||
|
|
|
@ -280,8 +280,7 @@ public abstract class AbstractCollectionPersister
|
|||
// isSet = collectionBinding.isSet();
|
||||
// isSorted = collectionBinding.isSorted();
|
||||
isPrimitiveArray = collectionBootDescriptor.isPrimitiveArray();
|
||||
subselectLoadable = collectionBootDescriptor.isSubselectLoadable()
|
||||
|| factory.getSessionFactoryOptions().isSubselectFetchEnabled();
|
||||
subselectLoadable = collectionBootDescriptor.isSubselectLoadable();
|
||||
|
||||
qualifiedTableName = determineTableName( table );
|
||||
|
||||
|
@ -310,11 +309,7 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
hasOrphanDelete = collectionBootDescriptor.hasOrphanDelete();
|
||||
|
||||
int batch = collectionBootDescriptor.getBatchSize();
|
||||
if ( batch == -1 ) {
|
||||
batch = creationContext.getSessionFactoryOptions().getDefaultBatchFetchSize();
|
||||
}
|
||||
batchSize = batch;
|
||||
batchSize = collectionBootDescriptor.getBatchSize();
|
||||
|
||||
isVersioned = collectionBootDescriptor.isOptimisticLocked();
|
||||
|
||||
|
@ -620,7 +615,7 @@ public abstract class AbstractCollectionPersister
|
|||
@Override
|
||||
public void postInstantiate() throws MappingException {
|
||||
if ( queryLoaderName == null ) {
|
||||
collectionLoader = createCollectionLoader( LoadQueryInfluencers.NONE );
|
||||
collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
else {
|
||||
// We pass null as metamodel because we did the initialization during construction already
|
||||
|
@ -632,8 +627,8 @@ public abstract class AbstractCollectionPersister
|
|||
if ( attributeMapping.getIndexDescriptor() != null ) {
|
||||
collectionElementLoaderByIndex = new CollectionElementLoaderByIndex(
|
||||
attributeMapping,
|
||||
LoadQueryInfluencers.NONE,
|
||||
getFactory()
|
||||
new LoadQueryInfluencers( factory ),
|
||||
factory
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -691,7 +686,7 @@ public abstract class AbstractCollectionPersister
|
|||
localCopy = collectionLoader;
|
||||
}
|
||||
else {
|
||||
localCopy = createCollectionLoader( LoadQueryInfluencers.NONE );
|
||||
localCopy = createCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
standardCollectionLoader = localCopy;
|
||||
}
|
||||
|
@ -753,7 +748,7 @@ public abstract class AbstractCollectionPersister
|
|||
protected CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( canUseReusableCollectionLoader( loadQueryInfluencers ) ) {
|
||||
if ( reusableCollectionLoader == null ) {
|
||||
reusableCollectionLoader = generateCollectionLoader( LoadQueryInfluencers.NONE );
|
||||
reusableCollectionLoader = generateCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
return reusableCollectionLoader;
|
||||
}
|
||||
|
@ -769,8 +764,8 @@ public abstract class AbstractCollectionPersister
|
|||
}
|
||||
|
||||
private CollectionLoader generateCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
|
||||
if ( batchSize > 1 ) {
|
||||
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
|
||||
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
|
||||
return getFactory().getServiceRegistry()
|
||||
.getService( BatchLoaderFactory.class )
|
||||
.createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, getFactory() );
|
||||
|
@ -894,8 +889,8 @@ public abstract class AbstractCollectionPersister
|
|||
LockOptions.NONE,
|
||||
(fetchParent, creationState) -> ImmutableFetchList.EMPTY,
|
||||
true,
|
||||
LoadQueryInfluencers.NONE,
|
||||
getFactory()
|
||||
new LoadQueryInfluencers( factory ),
|
||||
factory
|
||||
);
|
||||
|
||||
final NavigablePath entityPath = new NavigablePath( attributeMapping.getRootPathName() );
|
||||
|
@ -1525,6 +1520,11 @@ public abstract class AbstractCollectionPersister
|
|||
return batchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBatchLoadable() {
|
||||
return batchSize > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMappedByProperty() {
|
||||
return mappedByProperty;
|
||||
|
|
|
@ -310,7 +310,10 @@ public interface CollectionPersister extends Restrictable {
|
|||
boolean elementExists(Object key, Object element, SharedSessionContractImplementor session);
|
||||
Object getElementByIndex(Object key, Object index, SharedSessionContractImplementor session, Object owner);
|
||||
default int getBatchSize() {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
default boolean isBatchLoadable() {
|
||||
return getBatchSize() > 1;
|
||||
}
|
||||
default boolean isSubselectLoadable() {
|
||||
return false;
|
||||
|
|
|
@ -110,7 +110,6 @@ import org.hibernate.internal.CoreLogging;
|
|||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.FilterAliasGenerator;
|
||||
import org.hibernate.internal.FilterHelper;
|
||||
import org.hibernate.internal.FilterImpl;
|
||||
import org.hibernate.internal.util.IndexedConsumer;
|
||||
import org.hibernate.internal.util.LazyValue;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
@ -507,13 +506,8 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
final Dialect dialect = creationContext.getDialect();
|
||||
|
||||
int batch = persistentClass.getBatchSize();
|
||||
if ( batch == -1 ) {
|
||||
batch = creationContext.getSessionFactoryOptions().getDefaultBatchFetchSize();
|
||||
}
|
||||
batchSize = batch;
|
||||
hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections()
|
||||
|| entityMetamodel.hasCollections() && factory.getSessionFactoryOptions().isSubselectFetchEnabled();
|
||||
batchSize = persistentClass.getBatchSize();
|
||||
hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections();
|
||||
hasPartitionedSelectionMapping = persistentClass.hasPartitionedSelectionMapping();
|
||||
hasCollectionNotReferencingPK = persistentClass.hasCollectionNotReferencingPK();
|
||||
|
||||
|
@ -532,19 +526,17 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
if ( persistentClass.getLoaderName() != null ) {
|
||||
// We must resolve the named query on-demand through the boot model because it isn't initialized yet
|
||||
final NamedQueryMemento namedQueryMemento = factory.getQueryEngine().getNamedObjectRepository()
|
||||
.resolve( factory, creationContext.getBootModel(), persistentClass.getLoaderName() );
|
||||
final NamedQueryMemento namedQueryMemento =
|
||||
factory.getQueryEngine().getNamedObjectRepository()
|
||||
.resolve( factory, creationContext.getBootModel(), persistentClass.getLoaderName() );
|
||||
if ( namedQueryMemento == null ) {
|
||||
throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName()
|
||||
+ "] : " + persistentClass.getLoaderName() );
|
||||
}
|
||||
singleIdLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, namedQueryMemento );
|
||||
}
|
||||
else if ( batchSize > 1 ) {
|
||||
singleIdLoader = createBatchingIdEntityLoader( this, batchSize, factory );
|
||||
}
|
||||
else {
|
||||
singleIdLoader = new SingleIdEntityLoaderStandardImpl<>( this, factory );
|
||||
singleIdLoader = createSingleIdEntityLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
|
||||
multiIdLoader = buildMultiIdLoader( persistentClass );
|
||||
|
@ -815,6 +807,16 @@ public abstract class AbstractEntityPersister
|
|||
fullDiscriminatorValues = toObjectArray( values );
|
||||
}
|
||||
|
||||
private SingleIdEntityLoader<?> createSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
|
||||
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
|
||||
return createBatchingIdEntityLoader( this, batchSize, factory );
|
||||
}
|
||||
else {
|
||||
return new SingleIdEntityLoaderStandardImpl<>( this, factory );
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> getEntityNameByTableNameMap(PersistentClass persistentClass) {
|
||||
final Map<String, String> entityNameByTableNameMap = new HashMap<>();
|
||||
PersistentClass superType = persistentClass.getSuperPersistentClass();
|
||||
|
@ -1188,7 +1190,7 @@ public abstract class AbstractEntityPersister
|
|||
getIdentifierMapping(),
|
||||
null,
|
||||
1,
|
||||
LoadQueryInfluencers.NONE,
|
||||
new LoadQueryInfluencers( factory ),
|
||||
LockOptions.NONE,
|
||||
jdbcParameters::add,
|
||||
factory
|
||||
|
@ -1643,6 +1645,11 @@ public abstract class AbstractEntityPersister
|
|||
return batchSize > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getIdentifierColumnNames() {
|
||||
return rootTableKeyColumnNames;
|
||||
|
@ -1707,8 +1714,8 @@ public abstract class AbstractEntityPersister
|
|||
LockOptions.NONE,
|
||||
this::fetchProcessor,
|
||||
true,
|
||||
LoadQueryInfluencers.NONE,
|
||||
getFactory()
|
||||
new LoadQueryInfluencers( factory ),
|
||||
factory
|
||||
);
|
||||
|
||||
final NavigablePath entityPath = new NavigablePath( getRootPathName() );
|
||||
|
|
|
@ -749,9 +749,22 @@ public interface EntityPersister extends EntityMappingType, RootTableGroupProduc
|
|||
ClassMetadata getClassMetadata();
|
||||
|
||||
/**
|
||||
* Is batch loading enabled?
|
||||
* The batch size for batch loading.
|
||||
*
|
||||
* @see org.hibernate.engine.spi.LoadQueryInfluencers#effectiveBatchSize(EntityPersister)
|
||||
*/
|
||||
boolean isBatchLoadable();
|
||||
default int getBatchSize() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is batch loading enabled?
|
||||
*
|
||||
* @see org.hibernate.engine.spi.LoadQueryInfluencers#effectivelyBatchLoadable(EntityPersister)
|
||||
*/
|
||||
default boolean isBatchLoadable() {
|
||||
return getBatchSize() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is select snapshot before update enabled?
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
|
|||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
|
@ -75,6 +76,11 @@ public class JdbcValuesMappingImpl extends StandardJdbcValuesMapping {
|
|||
public SqlAstCreationContext getSqlAstCreationContext() {
|
||||
return creationState.getSqlAstCreationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionContext getExecutionContext() {
|
||||
return creationState.getExecutionContext();
|
||||
}
|
||||
};
|
||||
}
|
||||
return super.resolveAssemblers( finalCreationState );
|
||||
|
|
|
@ -66,7 +66,7 @@ public class FakeSqmToSqlAstConverter extends BaseSemanticQueryWalker implements
|
|||
|
||||
@Override
|
||||
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
||||
return LoadQueryInfluencers.NONE;
|
||||
return new LoadQueryInfluencers( getCreationContext().getSessionFactory() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -30,4 +31,6 @@ public interface AssemblerCreationState {
|
|||
Supplier<Initializer> producer);
|
||||
|
||||
SqlAstCreationContext getSqlAstCreationContext();
|
||||
|
||||
ExecutionContext getExecutionContext();
|
||||
}
|
||||
|
|
|
@ -351,9 +351,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
// 2) build the EntityKey
|
||||
entityKey = new EntityKey( id, concreteDescriptor );
|
||||
// 3) schedule the EntityKey for batch loading, if possible
|
||||
if ( concreteDescriptor.isBatchLoadable() ) {
|
||||
|
||||
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( concreteDescriptor ) ) {
|
||||
final PersistenceContext persistenceContext =
|
||||
rowProcessingState.getSession().getPersistenceContextInternal();
|
||||
session.getPersistenceContextInternal();
|
||||
if ( !persistenceContext.containsEntity( entityKey ) ) {
|
||||
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ import org.hibernate.sql.results.graph.DomainResult;
|
|||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
|
||||
|
||||
import static org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializerBuilder.BatchMode.BATCH_INITIALIZE;
|
||||
import static org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializerBuilder.BatchMode.BATCH_LOAD;
|
||||
import static org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializerBuilder.BatchMode.NONE;
|
||||
|
||||
public class EntitySelectFetchInitializerBuilder {
|
||||
|
||||
public static AbstractFetchParentAccess createInitializer(
|
||||
|
@ -83,8 +87,12 @@ public class EntitySelectFetchInitializerBuilder {
|
|||
EntityPersister entityPersister,
|
||||
FetchParentAccess parentAccess,
|
||||
AssemblerCreationState creationState) {
|
||||
if ( !entityPersister.isBatchLoadable() || creationState.isScrollResult() ) {
|
||||
return BatchMode.NONE;
|
||||
if ( creationState.isScrollResult()
|
||||
|| !creationState.getExecutionContext()
|
||||
.getSession()
|
||||
.getLoadQueryInfluencers()
|
||||
.effectivelyBatchLoadable( entityPersister ) ) {
|
||||
return NONE;
|
||||
}
|
||||
while ( parentAccess.isEmbeddableInitializer() ) {
|
||||
final EmbeddableInitializer embeddableInitializer = parentAccess.asEmbeddableInitializer();
|
||||
|
@ -95,9 +103,11 @@ public class EntitySelectFetchInitializerBuilder {
|
|||
if ( initializedPart.isEntityIdentifierMapping()
|
||||
// todo: check if the virtual check is necessary
|
||||
|| initializedPart.isVirtual()
|
||||
// If the parent embeddable has a custom instantiator, we can't inject entities later through setValues()
|
||||
|| !( initializedPart.getMappedType().getRepresentationStrategy().getInstantiator() instanceof StandardEmbeddableInstantiator ) ) {
|
||||
return entityPersister.hasSubclasses() ? BatchMode.NONE : BatchMode.BATCH_INITIALIZE;
|
||||
// If the parent embeddable has a custom instantiator,
|
||||
// we can't inject entities later through setValues()
|
||||
|| !( initializedPart.getMappedType().getRepresentationStrategy().getInstantiator()
|
||||
instanceof StandardEmbeddableInstantiator ) ) {
|
||||
return entityPersister.hasSubclasses() ? NONE : BATCH_INITIALIZE;
|
||||
}
|
||||
parentAccess = parentAccess.getFetchParentAccess();
|
||||
if ( parentAccess == null ) {
|
||||
|
@ -111,10 +121,10 @@ public class EntitySelectFetchInitializerBuilder {
|
|||
if ( cacheAccess != null ) {
|
||||
// Do batch initialization instead of batch loading if the parent entity is cacheable
|
||||
// to avoid putting entity state into the cache at a point when the association is not yet set
|
||||
return BatchMode.BATCH_INITIALIZE;
|
||||
return BATCH_INITIALIZE;
|
||||
}
|
||||
}
|
||||
return BatchMode.BATCH_LOAD;
|
||||
return BATCH_LOAD;
|
||||
}
|
||||
|
||||
enum BatchMode {
|
||||
|
|
|
@ -121,6 +121,11 @@ public class ResultsHelper {
|
|||
public SqlAstCreationContext getSqlAstCreationContext() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionContext getExecutionContext() {
|
||||
return executionContext;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ public class ManyToOneType extends EntityType {
|
|||
//cannot batch fetch by unique key (property-ref associations)
|
||||
if ( uniqueKeyPropertyName == null && id != null ) {
|
||||
final EntityPersister persister = getAssociatedEntityPersister( session.getFactory() );
|
||||
if ( persister.isBatchLoadable() ) {
|
||||
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( persister ) ) {
|
||||
final EntityKey entityKey = session.generateEntityKey( id, persister );
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
if ( !persistenceContext.containsEntity( entityKey ) ) {
|
||||
|
|
|
@ -529,11 +529,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBatchLoadable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelectBeforeUpdateRequired() {
|
||||
return false;
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.hibernate.engine.spi.AbstractDelegatingSharedSessionBuilder;
|
|||
@SuppressWarnings("unused")
|
||||
public class TestDelegatingSharedSessionBuilder extends AbstractDelegatingSharedSessionBuilder {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public TestDelegatingSharedSessionBuilder(SharedSessionBuilder delegate) {
|
||||
super( delegate );
|
||||
}
|
||||
|
|
|
@ -545,11 +545,6 @@ public class PersisterClassProviderTest {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBatchLoadable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelectBeforeUpdateRequired() {
|
||||
return false;
|
||||
|
|
|
@ -616,10 +616,6 @@ public class CustomPersister implements EntityPersister {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean isBatchLoadable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Type getPropertyType(String propertyName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue