下面列出了org.hibernate.cache.spi.access.SoftLock#org.hibernate.event.spi.LoadEventListener 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private CompletionStage<Object> doOnLoad(
final EntityPersister persister,
final LoadEvent event,
final LoadEventListener.LoadType loadType) {
final EventSource session = event.getSession();
final EntityKey keyToLoad = session.generateEntityKey( event.getEntityId(), persister );
if ( loadType.isNakedEntityReturned() ) {
//do not return a proxy!
//(this option indicates we are initializing a proxy)
return load( event, persister, keyToLoad, loadType );
}
//return a proxy if appropriate
else if ( event.getLockMode() == LockMode.NONE ) {
return proxyOrLoad( event, persister, keyToLoad, loadType );
}
else {
return lockAndLoad( event, persister, keyToLoad, loadType, session );
}
}
@Override
public void load(Object object, Serializable id) throws HibernateException {
LoadEvent event = loadEvent;
loadEvent = null;
if ( event == null ) {
event = new LoadEvent( id, object, this );
}
else {
event.setEntityClassName( null );
event.setEntityId( id );
event.setInstanceToLoad( object );
event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE );
event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() );
event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() );
}
fireLoad( event, LoadEventListener.RELOAD );
if ( loadEvent == null ) {
event.setEntityClassName( null );
event.setEntityId( null );
event.setInstanceToLoad( null );
event.setResult( null );
loadEvent = event;
}
}
/**
* Load the data for the object with the specified id into a newly created object.
* This is only called when lazily initializing a proxy.
* Do NOT return a proxy.
*/
@Override
public Object immediateLoad(String entityName, Serializable id) throws HibernateException {
if ( log.isDebugEnabled() ) {
EntityPersister persister = getFactory().getMetamodel().entityPersister( entityName );
log.debugf( "Initializing proxy: %s", MessageHelper.infoString( persister, id, getFactory() ) );
}
LoadEvent event = loadEvent;
loadEvent = null;
event = recycleEventInstance( event, id, entityName );
fireLoad( event, LoadEventListener.IMMEDIATE_LOAD );
Object result = event.getResult();
if ( loadEvent == null ) {
event.setEntityClassName( null );
event.setEntityId( null );
event.setInstanceToLoad( null );
event.setResult( null );
loadEvent = event;
}
return result;
}
/**
* Handle the given load event.
*
* @param event The load event to be handled.
*
* @throws HibernateException
*/
public void onLoad(
final LoadEvent event,
final LoadEventListener.LoadType loadType) throws HibernateException {
final EntityPersister persister = getPersister( event );
if ( persister == null ) {
throw new HibernateException( "Unable to locate persister: " + event.getEntityClassName() );
}
final Class idClass = persister.getIdentifierType().getReturnedClass();
if ( idClass != null &&
!idClass.isInstance( event.getEntityId() ) &&
!DelayedPostInsertIdentifier.class.isInstance( event.getEntityId() ) ) {
checkIdClass( persister, event, loadType, idClass );
}
doOnLoad( persister, event, loadType );
}
private void loadByDerivedIdentitySimplePkValue(
LoadEvent event,
LoadEventListener.LoadType options,
EntityPersister dependentPersister,
EmbeddedComponentType dependentIdType,
EntityPersister parentPersister) {
final EntityKey parentEntityKey = event.getSession().generateEntityKey( event.getEntityId(), parentPersister );
final Object parent = doLoad( event, parentPersister, parentEntityKey, options );
final Serializable dependent = (Serializable) dependentIdType.instantiate( parent, event.getSession() );
dependentIdType.setPropertyValues( dependent, new Object[] {parent}, dependentPersister.getEntityMode() );
final EntityKey dependentEntityKey = event.getSession().generateEntityKey( dependent, dependentPersister );
event.setEntityId( dependent );
event.setResult( doLoad( event, dependentPersister, dependentEntityKey, options ) );
}
/**
* Handle the given load event.
*
* @param event The load event to be handled.
*/
@Override
public CompletionStage<Void> reactiveOnLoad(
final LoadEvent event,
final LoadEventListener.LoadType loadType) throws HibernateException {
final EntityPersister persister = getPersister( event );
if ( persister == null ) {
throw new HibernateException( "Unable to locate persister: " + event.getEntityClassName() );
}
return checkId( event, loadType, persister ).thenCompose(
vd -> doOnLoad( persister, event, loadType )
.thenAccept( event::setResult )
.handle( (v, x) -> {
if ( x instanceof HibernateException ) {
LOG.unableToLoadCommand( (HibernateException) x );
}
CompletionStages.returnNullorRethrow( x );
if ( event.getResult() instanceof CompletionStage ) {
throw new AssertionFailure( "Unexpected CompletionStage" );
}
return v;
} ));
}
private CompletionStage<Void> checkIdClass(
final EntityPersister persister,
final LoadEvent event,
final LoadEventListener.LoadType loadType,
final Class<?> idClass) {
// we may have the kooky jpa requirement of allowing find-by-id where
// "id" is the "simple pk value" of a dependent objects parent. This
// is part of its generally goofy "derived identity" "feature"
final IdentifierProperty identifierProperty = persister.getEntityMetamodel().getIdentifierProperty();
if ( identifierProperty.isEmbedded() ) {
final EmbeddedComponentType dependentIdType = (EmbeddedComponentType) identifierProperty.getType();
if ( dependentIdType.getSubtypes().length == 1 ) {
final Type singleSubType = dependentIdType.getSubtypes()[0];
if ( singleSubType.isEntityType() ) {
final EntityType dependentParentType = (EntityType) singleSubType;
final SessionFactoryImplementor factory = event.getSession().getFactory();
final Type dependentParentIdType = dependentParentType.getIdentifierOrUniqueKeyType( factory );
if ( dependentParentIdType.getReturnedClass().isInstance( event.getEntityId() ) ) {
// yep that's what we have...
return loadByDerivedIdentitySimplePkValue( event, loadType, persister,
dependentIdType, factory.getMetamodel().entityPersister( dependentParentType.getAssociatedEntityName() )
);
}
}
}
}
throw new TypeMismatchException(
"Provided id of the wrong type for class " + persister.getEntityName() + ". Expected: " + idClass + ", got " + event.getEntityId().getClass() );
}
private CompletionStage<Void> loadByDerivedIdentitySimplePkValue(LoadEvent event, LoadEventListener.LoadType options,
EntityPersister dependentPersister, EmbeddedComponentType dependentIdType, EntityPersister parentPersister) {
EventSource session = event.getSession();
final EntityKey parentEntityKey = session.generateEntityKey( event.getEntityId(), parentPersister );
return doLoad( event, parentPersister, parentEntityKey, options )
.thenApply( checkEntityFound( session, parentEntityKey.getEntityName(), parentEntityKey ) )
.thenApply( parent -> {
final Serializable dependent = (Serializable) dependentIdType.instantiate( parent, session );
dependentIdType.setPropertyValues( dependent, new Object[] {parent}, dependentPersister.getEntityMode() );
event.setEntityId( dependent );
return session.generateEntityKey( dependent, dependentPersister );
} )
.thenCompose( dependentEntityKey -> doLoad( event, dependentPersister, dependentEntityKey, options ) )
.thenAccept( event::setResult );
}
/**
* Given a proxy, initialize it and/or narrow it provided either
* is necessary.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param persistenceContext The originating session
* @param proxy The proxy to narrow
*
* @return The created/existing proxy
*/
private CompletionStage<Object> returnNarrowedProxy(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext,
final Object proxy) {
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Entity proxy found in session cache" );
}
LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
if ( li.isUnwrap() ) {
return CompletionStages.completedFuture( li.getImplementation() );
}
CompletionStage<Object> implStage;
if ( !options.isAllowProxyCreation() ) {
implStage = load( event, persister, keyToLoad, options )
.thenApply( optional -> {
if ( optional == null ) {
event.getSession()
.getFactory()
.getEntityNotFoundDelegate()
.handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier() );
}
return optional;
} );
}
else {
implStage = CompletionStages.nullFuture();
}
return implStage.thenApply( impl -> persistenceContext.narrowProxy( proxy, persister, keyToLoad, impl ) );
}
/**
* If there is already a corresponding proxy associated with the
* persistence context, return it; otherwise create a proxy, associate it
* with the persistence context, and return the just-created proxy.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param persistenceContext The originating session
*
* @return The created/existing proxy
*/
private Object createProxyIfNecessary(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext) {
Object existing = persistenceContext.getEntity( keyToLoad );
final boolean traceEnabled = LOG.isTraceEnabled();
if ( existing != null ) {
// return existing object or initialized proxy (unless deleted)
if ( traceEnabled ) {
LOG.trace( "Entity found in session cache" );
}
if ( options.isCheckDeleted() ) {
EntityEntry entry = persistenceContext.getEntry( existing );
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return null;
}
}
return existing;
}
if ( traceEnabled ) {
LOG.trace( "Creating new proxy for entity" );
}
return createProxy( event, persister, keyToLoad, persistenceContext );
}
@Override
public final Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable)
throws HibernateException {
// todo : remove
LoadEventListener.LoadType type = nullable
? LoadEventListener.INTERNAL_LOAD_NULLABLE
: eager
? LoadEventListener.INTERNAL_LOAD_EAGER
: LoadEventListener.INTERNAL_LOAD_LAZY;
LoadEvent event = loadEvent;
loadEvent = null;
event = recycleEventInstance( event, id, entityName );
fireLoad( event, type );
Object result = event.getResult();
if ( !nullable ) {
UnresolvableObjectException.throwIfNull( result, id, entityName );
}
if ( loadEvent == null ) {
event.setEntityClassName( null );
event.setEntityId( null );
event.setInstanceToLoad( null );
event.setResult( null );
loadEvent = event;
}
return result;
}
private void fireLoad(LoadEvent event, LoadType loadType) {
checkOpenOrWaitingForAutoClose();
checkTransactionSynchStatus();
for ( LoadEventListener listener : listeners( EventType.LOAD ) ) {
listener.onLoad( event, loadType );
}
delayedAfterCompletion();
}
private void doOnLoad(
final EntityPersister persister,
final LoadEvent event,
final LoadEventListener.LoadType loadType) {
try {
final EntityKey keyToLoad = event.getSession().generateEntityKey( event.getEntityId(), persister );
if ( loadType.isNakedEntityReturned() ) {
//do not return a proxy!
//(this option indicates we are initializing a proxy)
event.setResult( load( event, persister, keyToLoad, loadType ) );
}
else {
//return a proxy if appropriate
if ( event.getLockMode() == LockMode.NONE ) {
event.setResult( proxyOrLoad( event, persister, keyToLoad, loadType ) );
}
else {
event.setResult( lockAndLoad( event, persister, keyToLoad, loadType, event.getSession() ) );
}
}
}
catch (HibernateException e) {
LOG.unableToLoadCommand( e );
throw e;
}
}
private void checkIdClass(
final EntityPersister persister,
final LoadEvent event,
final LoadEventListener.LoadType loadType,
final Class idClass) {
// we may have the kooky jpa requirement of allowing find-by-id where
// "id" is the "simple pk value" of a dependent objects parent. This
// is part of its generally goofy "derived identity" "feature"
if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
final EmbeddedComponentType dependentIdType =
(EmbeddedComponentType) persister.getEntityMetamodel().getIdentifierProperty().getType();
if ( dependentIdType.getSubtypes().length == 1 ) {
final Type singleSubType = dependentIdType.getSubtypes()[0];
if ( singleSubType.isEntityType() ) {
final EntityType dependentParentType = (EntityType) singleSubType;
final Type dependentParentIdType = dependentParentType.getIdentifierOrUniqueKeyType( event.getSession().getFactory() );
if ( dependentParentIdType.getReturnedClass().isInstance( event.getEntityId() ) ) {
// yep that's what we have...
loadByDerivedIdentitySimplePkValue(
event,
loadType,
persister,
dependentIdType,
event.getSession().getFactory().getEntityPersister( dependentParentType.getAssociatedEntityName() )
);
return;
}
}
}
}
throw new TypeMismatchException(
"Provided id of the wrong type for class " + persister.getEntityName() + ". Expected: " + idClass
+ ", got " + event.getEntityId().getClass()
);
}
/**
* Performs the load of an entity.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
*
* @return The loaded entity.
*
* @throws HibernateException
*/
private Object load(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {
if ( event.getInstanceToLoad() != null ) {
if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
throw new PersistentObjectException(
"attempted to load into an instance that was already associated with the session: " +
MessageHelper.infoString(
persister,
event.getEntityId(),
event.getSession().getFactory()
)
);
}
persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession() );
}
final Object entity = doLoad( event, persister, keyToLoad, options );
boolean isOptionalInstance = event.getInstanceToLoad() != null;
if ( entity == null && ( !options.isAllowNulls() || isOptionalInstance ) ) {
event.getSession()
.getFactory()
.getEntityNotFoundDelegate()
.handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
}
else if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
}
return entity;
}
/**
* Based on configured options, will either return a pre-existing proxy,
* generate a new proxy, or perform an actual load.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
*
* @return The result of the proxy/load operation.
*/
private Object proxyOrLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {
if ( traceEnabled ) {
LOG.tracev(
"Loading entity: {0}",
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
// this class has no proxies (so do a shortcut)
if ( !persister.hasProxy() ) {
return load( event, persister, keyToLoad, options );
}
final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();
// look for a proxy
Object proxy = persistenceContext.getProxy( keyToLoad );
if ( proxy != null ) {
return returnNarrowedProxy( event, persister, keyToLoad, options, persistenceContext, proxy );
}
if ( options.isAllowProxyCreation() ) {
return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
}
// return a newly loaded object
return load( event, persister, keyToLoad, options );
}
/**
* Given a proxy, initialize it and/or narrow it provided either
* is necessary.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param persistenceContext The originating session
* @param proxy The proxy to narrow
*
* @return The created/existing proxy
*/
private Object returnNarrowedProxy(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext,
final Object proxy) {
if ( traceEnabled ) {
LOG.trace( "Entity proxy found in session cache" );
}
LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
if ( li.isUnwrap() ) {
return li.getImplementation();
}
Object impl = null;
if ( !options.isAllowProxyCreation() ) {
impl = load( event, persister, keyToLoad, options );
if ( impl == null ) {
event.getSession()
.getFactory()
.getEntityNotFoundDelegate()
.handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier() );
}
}
return persistenceContext.narrowProxy( proxy, persister, keyToLoad, impl );
}
/**
* If there is already a corresponding proxy associated with the
* persistence context, return it; otherwise create a proxy, associate it
* with the persistence context, and return the just-created proxy.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param persistenceContext The originating session
*
* @return The created/existing proxy
*/
private Object createProxyIfNecessary(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext) {
Object existing = persistenceContext.getEntity( keyToLoad );
if ( existing != null ) {
// return existing object or initialized proxy (unless deleted)
if ( traceEnabled ) {
LOG.trace( "Entity found in session cache" );
}
if ( options.isCheckDeleted() ) {
EntityEntry entry = persistenceContext.getEntry( existing );
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return null;
}
}
return existing;
}
if ( traceEnabled ) {
LOG.trace( "Creating new proxy for entity" );
}
// return new uninitialized proxy
Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
persistenceContext.addProxy( keyToLoad, proxy );
return proxy;
}
/**
* If the class to be loaded has been configured with a cache, then lock
* given id in that cache and then perform the load.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param source The originating session
*
* @return The loaded entity
*
* @throws HibernateException
*/
private Object lockAndLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final SessionImplementor source) {
SoftLock lock = null;
final Object ck;
final EntityDataAccess cache = persister.getCacheAccessStrategy();
if ( persister.canWriteToCache() ) {
ck = cache.generateCacheKey(
event.getEntityId(),
persister,
source.getFactory(),
source.getTenantIdentifier()
);
lock = persister.getCacheAccessStrategy().lockItem( source, ck, null );
}
else {
ck = null;
}
Object entity;
try {
entity = load( event, persister, keyToLoad, options );
}
finally {
if ( persister.canWriteToCache() ) {
cache.unlockItem( source, ck, lock );
}
}
return event.getSession().getPersistenceContext().proxyFor( persister, keyToLoad, entity );
}
/**
* Attempts to locate the entity in the session-level cache.
* <p/>
* If allowed to return nulls, then if the entity happens to be found in
* the session cache, we check the entity type for proper handling
* of entity hierarchies.
* <p/>
* If checkDeleted was set to true, then if the entity is found in the
* session-level cache, it's current status within the session cache
* is checked to see if it has previously been scheduled for deletion.
*
* @param event The load event
* @param keyToLoad The EntityKey representing the entity to be loaded.
* @param options The load options.
*
* @return The entity from the session-level cache, or null.
*
* @throws HibernateException Generally indicates problems applying a lock-mode.
*/
protected Object loadFromSessionCache(
final LoadEvent event,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) throws HibernateException {
SessionImplementor session = event.getSession();
Object old = session.getEntityUsingInterceptor( keyToLoad );
if ( old != null ) {
// this object was already loaded
EntityEntry oldEntry = session.getPersistenceContext().getEntry( old );
if ( options.isCheckDeleted() ) {
Status status = oldEntry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return REMOVED_ENTITY_MARKER;
}
}
if ( options.isAllowNulls() ) {
final EntityPersister persister = event.getSession()
.getFactory()
.getEntityPersister( keyToLoad.getEntityName() );
if ( !persister.isInstance( old ) ) {
return INCONSISTENT_RTN_CLASS_MARKER;
}
}
upgradeLock( old, oldEntry, event.getLockOptions(), event.getSession() );
}
return old;
}
private CompletionStage<Void> fireLoad(LoadEvent event, LoadEventListener.LoadType loadType) {
checkOpenOrWaitingForAutoClose();
return fireLoadNoChecks( event, loadType )
.whenComplete( (v, e) -> delayedAfterCompletion() );
}
private CompletionStage<Void> fireLoadNoChecks(LoadEvent event, LoadEventListener.LoadType loadType) {
pulseTransactionCoordinator();
return fire(event, loadType, EventType.LOAD, (ReactiveLoadEventListener l) -> l::reactiveOnLoad);
}
public final CompletionStage<T> load(Serializable id) {
return perform( () -> doLoad( id, LoadEventListener.GET) );
}
public final CompletionStage<T> fetch(Serializable id) {
return perform( () -> doLoad( id, LoadEventListener.IMMEDIATE_LOAD) );
}
/**
* This method is not reactive but we expect it to be called only when a proxy can be returned.
* <p>
* In particular, it should be called only by
* {@link org.hibernate.internal.SessionImpl#internalLoad(String, Serializable, boolean, boolean)}.
* </p>
*
* @see org.hibernate.event.internal.DefaultLoadEventListener#onLoad(LoadEvent, LoadType)
* @throws UnsupportedOperationException if the entity loaded is not a proxy
*/
@Override
public void onLoad(
final LoadEvent event,
final LoadEventListener.LoadType loadType) throws HibernateException {
final EntityPersister persister = getPersister( event );
if ( persister == null ) {
throw new HibernateException( "Unable to locate persister: " + event.getEntityClassName() );
}
// Since this method is not reactive, we're not expecting to hit the
// database here (if we do, it's a bug) and so we can assume the
// returned CompletionStage is already completed
CompletionStage<Void> checkId = checkId( event, loadType, persister );
if ( !checkId.toCompletableFuture().isDone() ) {
// This only happens if the object is loaded from the db
throw new AssertionFailure( "Unexpected access to the database" );
}
try {
// Since this method is not reactive, we're not expecting to hit the
// database here (if we do, it's a bug) and so we can assume the
// returned CompletionStage is already completed (a proxy, perhaps)
CompletionStage<Object> loaded = doOnLoad( persister, event, loadType );
if ( !loaded.toCompletableFuture().isDone() ) {
// This only happens if the object is loaded from the db
throw new AssertionFailure( "Unexpected access to the database" );
}
else {
// Proxy
event.setResult( loaded.toCompletableFuture().getNow( null ) );
}
}
catch (HibernateException e) {
LOG.unableToLoadCommand( e );
throw e;
}
if ( event.getResult() instanceof CompletionStage ) {
throw new AssertionFailure( "Unexpected CompletionStage" );
}
}
/**
* If the class to be loaded has been configured with a cache, then lock
* given id in that cache and then perform the load.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param source The originating session
*
* @return The loaded entity
*/
private CompletionStage<Object> lockAndLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final SessionImplementor source) {
final SoftLock lock;
final Object ck;
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final boolean canWriteToCache = persister.canWriteToCache();
if ( canWriteToCache ) {
ck = cache.generateCacheKey(
event.getEntityId(),
persister,
source.getFactory(),
source.getTenantIdentifier()
);
lock = cache.lockItem( source, ck, null );
}
else {
ck = null;
lock = null;
}
try {
return load( event, persister, keyToLoad, options )
.whenComplete( (v, x) -> {
if ( canWriteToCache ) {
cache.unlockItem( source, ck, lock );
}
} )
.thenApply( entity -> source.getPersistenceContextInternal().proxyFor( persister, keyToLoad, entity ) );
}
catch (HibernateException he) {
//in case load() throws an exception
if ( canWriteToCache ) {
cache.unlockItem( source, ck, lock );
}
throw he;
}
}
/**
* Coordinates the efforts to load a given entity. First, an attempt is
* made to load the entity from the session-level cache. If not found there,
* an attempt is made to locate it in second-level cache. Lastly, an
* attempt is made to load it directly from the datasource.
*
* @param event The load event
* @param persister The persister for the entity being requested for load
* @param keyToLoad The EntityKey representing the entity to be loaded.
* @param options The load options.
*
* @return The loaded entity, or null.
*/
private CompletionStage<Object> doLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {
final EventSource session = event.getSession();
final boolean traceEnabled = LOG.isTraceEnabled();
if ( traceEnabled ) {
LOG.tracev(
"Attempting to resolve: {0}",
MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() )
);
}
CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry =
CacheEntityLoaderHelper.INSTANCE.loadFromSessionCache(
event,
keyToLoad,
options
);
Object entity = persistenceContextEntry.getEntity();
if ( entity != null ) {
Object managed = persistenceContextEntry.isManaged() ? entity : null;
return CompletionStages.completedFuture( managed );
}
entity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( event, persister, keyToLoad );
if ( entity != null ) {
if ( traceEnabled ) {
LOG.tracev(
"Resolved object in second-level cache: {0}",
MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() )
);
}
cacheNaturalId( event, persister, session, entity );
return CompletionStages.completedFuture( entity );
}
else {
if ( traceEnabled ) {
LOG.tracev(
"Object not resolved in any cache: {0}",
MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() )
);
}
return loadFromDatasource( event, persister )
.thenApply( optional -> {
if ( optional!=null ) {
cacheNaturalId( event, persister, session, optional );
}
return optional;
} );
}
}
/**
* Coordinates the efforts to load a given entity. First, an attempt is
* made to load the entity from the session-level cache. If not found there,
* an attempt is made to locate it in second-level cache. Lastly, an
* attempt is made to load it directly from the datasource.
*
* @param event The load event
* @param persister The persister for the entity being requested for load
* @param keyToLoad The EntityKey representing the entity to be loaded.
* @param options The load options.
*
* @return The loaded entity, or null.
*/
private Object doLoad(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {
if ( traceEnabled ) {
LOG.tracev(
"Attempting to resolve: {0}",
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
Object entity = loadFromSessionCache( event, keyToLoad, options );
if ( entity == REMOVED_ENTITY_MARKER ) {
LOG.debug( "Load request found matching entity in context, but it is scheduled for removal; returning null" );
return null;
}
if ( entity == INCONSISTENT_RTN_CLASS_MARKER ) {
LOG.debug(
"Load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null"
);
return null;
}
if ( entity != null ) {
if ( traceEnabled ) {
LOG.tracev(
"Resolved object in session cache: {0}",
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
return entity;
}
entity = loadFromSecondLevelCache( event, persister, keyToLoad );
if ( entity != null ) {
if ( traceEnabled ) {
LOG.tracev(
"Resolved object in second-level cache: {0}",
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
}
else {
if ( traceEnabled ) {
LOG.tracev(
"Object not resolved in any cache: {0}",
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
entity = loadFromDatasource( event, persister );
}
if ( entity != null && persister.hasNaturalIdentifier() ) {
event.getSession().getPersistenceContext().getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad(
persister,
event.getEntityId(),
event.getSession().getPersistenceContext().getNaturalIdHelper().extractNaturalIdValues(
entity,
persister
)
);
}
return entity;
}