many misc cleanups and doc for the Session hierarchy

This commit is contained in:
Gavin 2022-12-23 19:11:49 +01:00 committed by Gavin King
parent 974fe9e22d
commit fc62f33a55
15 changed files with 789 additions and 801 deletions

View File

@ -92,7 +92,7 @@ public final class Collections {
}
final EntityEntry e = persistenceContext.getEntry( owner );
//only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
if ( e != null && e.getStatus() != Status.DELETED && e.getStatus() != Status.GONE ) {
if ( e != null && !e.getStatus().isDeletedOrGone() ) {
throw new HibernateException(
"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: " +
loadedPersister.getRole()

View File

@ -27,7 +27,6 @@ import org.hibernate.MultiIdentifierLoadAccess;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.NaturalIdMultiLoadAccess;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.SessionEventListener;
import org.hibernate.SharedSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
@ -70,14 +69,13 @@ import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel;
/**
* This class is meant to be extended.
*
* Wraps and delegates all methods to a {@link SessionImplementor} and
* a {@link Session}. This is useful for custom implementations of this
* API so that only some methods need to be overridden
* A wrapper class that delegates all method invocations to a delegate instance of
* {@link SessionImplementor}. This is useful for custom implementations of that
* API, so that only some methods need to be overridden
* <p>
* (Used by Hibernate Search).
*
* @author <a href="mailto:sanne@hibernate.org">Sanne Grinovero</a> (C) 2012 Red Hat Inc.
* @author Sanne Grinovero
*/
@SuppressWarnings("deprecation")
public class SessionDelegatorBaseImpl implements SessionImplementor {
@ -89,8 +87,10 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
/**
* Returns the underlying delegate. Be careful that it has a different behavior from the {@link #getDelegate()}
* method coming from the EntityManager interface which returns the current session.
* Returns the delegate session.
* <p>
* @apiNote This returns a different object to the {@link #getDelegate()}
* method inherited from {@link jakarta.persistence.EntityManager}.
*
* @see SessionDelegatorBaseImpl#getDelegate()
*/
@ -650,11 +650,9 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
/**
* This is an implementation of EntityManager#getDelegate(). It returns the current session and not the delegate
* session as it is what we want. The name of the method is misleading here but, as it is part of JPA, we cannot do
* anything about it.
* <p>
* To get the underlying delegate, use {@link #delegate()} instead.
* This is the implementation of {@link jakarta.persistence.EntityManager#getDelegate()}.
* It returns this object and <em>not</em> what we call the "delegate" session here.
* To get the delegate session, use {@link #delegate()} instead.
*
* @see SessionDelegatorBaseImpl#delegate()
*/
@ -683,7 +681,6 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
return delegate.createStoredProcedureCall( procedureName, resultSetMappings );
}
@SuppressWarnings("rawtypes")
@Override
public SharedSessionBuilder sessionWithOptions() {
return delegate.sessionWithOptions();

View File

@ -9,43 +9,50 @@ package org.hibernate.engine.spi;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.MergeContext;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.type.descriptor.WrapperOptions;
/**
* Defines the "internal contract" for {@link Session} and other parts of Hibernate such
* as {@link org.hibernate.type.Type}, {@link EntityPersister}
* and {@link org.hibernate.persister.collection.CollectionPersister} implementations.
*
* A Session, through this interface and SharedSessionContractImplementor, implements:
* Defines the "internal contract" between {@link Session} and other parts of Hibernate
* including implementors of {@link org.hibernate.type.Type}, {@link EntityPersister},
* and {@link org.hibernate.persister.collection.CollectionPersister}.
* <p>
* The {@code Session}, via this interface and {@link SharedSessionContractImplementor},
* implements:
* <ul>
* <li>
* {@link org.hibernate.resource.jdbc.spi.JdbcSessionOwner} to drive the behavior
* of the {@link org.hibernate.resource.jdbc.spi.JdbcSessionContext} delegate
* {@link JdbcSessionOwner}, and so the session also acts as the orchestrator
* of a "JDBC session", and may be used to construct a {@link JdbcCoordinator}.
* </li>
* <li>
* {@link TransactionCoordinatorBuilder.Options}
* to drive the creation of the {@link TransactionCoordinator} delegate
* {@link TransactionCoordinatorBuilder.Options}, allowing the session to control
* the creation of the {@link TransactionCoordinator} delegate when it is passed
* as an argument to
* {@link org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder#buildTransactionCoordinator}
* </li>
* <li>
* {@link org.hibernate.engine.jdbc.LobCreationContext} to act as the context for
* JDBC LOB instance creation
* {@link LobCreationContext}, and so the session may act as the context for
* JDBC LOB instance creation.
* </li>
* <li>
* {@link org.hibernate.type.descriptor.WrapperOptions} to fulfill the behavior
* needed while binding/extracting values to/from JDBC as part of the {@code Type}
* contracts
* {@link WrapperOptions}, and so the session may influence the process of binding
* and extracting values to and from JDBC, which is performed by implementors of
* {@link org.hibernate.type.descriptor.jdbc.JdbcType}.
* </li>
* </ul>
*
* See also {@link org.hibernate.event.spi.EventSource} which extends this interface
* providing s bridge to the event generation features of {@link org.hibernate.event}.
* provides a bridge to the event generation features of {@link org.hibernate.event}.
*
* @author Gavin King
* @author Steve Ebersole
@ -69,12 +76,21 @@ public interface SessionImplementor extends Session, SharedSessionContractImplem
@Override
RootGraphImplementor<?> getEntityGraph(String graphName);
/**
* Get the {@link ActionQueue} associated with this session.
*/
ActionQueue getActionQueue();
Object instantiate(EntityPersister persister, Object id) throws HibernateException;
/**
* Initiate a flush to force deletion of a re-persisted entity.
*/
void forceFlush(EntityEntry e) throws HibernateException;
/**
* Cascade the lock operation to the given child entity.
*/
void lock(String entityName, Object child, LockOptions lockOptions);
/**

View File

@ -16,7 +16,9 @@ import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.StatelessSession;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.event.spi.EventSource;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.query.Query;
import org.hibernate.SharedSessionContract;
import org.hibernate.Transaction;
@ -36,27 +38,30 @@ import org.hibernate.type.spi.TypeConfiguration;
/**
* Defines the internal contract shared between {@link org.hibernate.Session} and
* {@link org.hibernate.StatelessSession} as used by other parts of Hibernate (such as
* {@link org.hibernate.type.Type}, {@link EntityPersister} and
* {@link org.hibernate.persister.collection.CollectionPersister} implementors
*
* A Session, through this interface and SharedSessionContractImplementor, implements:<ul>
* {@link org.hibernate.StatelessSession} as used by other parts of Hibernate,
* including implementors of {@link org.hibernate.type.Type}, {@link EntityPersister},
* and {@link org.hibernate.persister.collection.CollectionPersister}.
* <p>
* The {@code Session}, via this interface and {@link SharedSessionContractImplementor},
* implements:
* <ul>
* <li>
* {@link JdbcSessionOwner} to drive the behavior of a "JDBC session".
* Can therefor be used to construct a JdbcCoordinator, which (for now) models a "JDBC session"
* {@link JdbcSessionOwner}, and so the session also acts as the orchestrator
* of a "JDBC session", and may be used to construct a {@link JdbcCoordinator}.
* </li>
* <li>
* {@link Options}
* to drive the creation of the {@link TransactionCoordinator} delegate.
* This allows it to be passed along to
* {@link Options}, allowing the session to control the creation of the
* {@link TransactionCoordinator} delegate when it is passed as an argument to
* {@link org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder#buildTransactionCoordinator}
* </li>
* <li>
* {@link LobCreationContext} to act as the context for JDBC LOB instance creation
* {@link LobCreationContext}, and so the session may act as the context for
* JDBC LOB instance creation.
* </li>
* <li>
* {@link WrapperOptions} to fulfill the behavior needed while
* binding/extracting values to/from JDBC as part of the Type contracts
* {@link WrapperOptions}, and so the session may influence the process of binding
* and extracting values to and from JDBC, which is performed by implementors of
* {@link org.hibernate.type.descriptor.jdbc.JdbcType}.
* </li>
* </ul>
*
@ -64,100 +69,117 @@ import org.hibernate.type.spi.TypeConfiguration;
* @author Steve Ebersole
*/
public interface SharedSessionContractImplementor
extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions, QueryProducerImplementor, JavaType.CoercionContext {
extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions,
QueryProducerImplementor, JavaType.CoercionContext {
// todo : this is the shared contract between Session and StatelessSession, but it defines methods that StatelessSession does not implement
// (it just throws UnsupportedOperationException). To me it seems like it is better to properly isolate those methods
// todo : this is the shared contract between Session and StatelessSession,
// but it defines methods that StatelessSession does not implement
// To me it seems like it is better to properly isolate those methods
// into just the Session hierarchy. They include (at least):
// 1) get/set CacheMode
// 2) get/set FlushMode
// 3) get/set (default) read-only
// 4) #setAutoClear
// 5) #disableTransactionAutoJoin
/**
* Get the creating {@code SessionFactoryImplementor}
* Obtain the {@linkplain SessionFactoryImplementor factory} which created this session.
*/
SessionFactoryImplementor getFactory();
/**
* Obtain the {@linkplain SessionFactoryImplementor factory} which created this session.
*/
@Override
default SessionFactoryImplementor getSessionFactory() {
return getFactory();
}
/**
* Obtain the {@link TypeConfiguration} for the factory which created this session.
*/
@Override
default TypeConfiguration getTypeConfiguration() {
return getFactory().getTypeConfiguration();
}
/**
* Get the {@link SessionEventListenerManager} associated with this session.
*/
SessionEventListenerManager getEventListenerManager();
/**
* Get the persistence context for this session.
* See also {@link #getPersistenceContextInternal()} for
* an alternative.
* <p>
* See {@link #getPersistenceContextInternal()} for
* a faster alternative.
*
* This method is not extremely fast: if you need to access
* the PersistenceContext multiple times, prefer keeping
* a reference to it over invoking this method multiple times.
* @implNote This method is not extremely fast: if you need to
* call the {@link PersistenceContext} multiple times,
* prefer keeping a reference to it instead of invoking
* this method multiple times.
*/
PersistenceContext getPersistenceContext();
/**
* Obtain the {@link JdbcCoordinator} for this session.
*/
JdbcCoordinator getJdbcCoordinator();
/**
* Obtain the {@link JdbcServices} for the factory which created this session.
*/
JdbcServices getJdbcServices();
/**
* The multi-tenancy tenant identifier, if one.
*
* @return The tenant identifier; may be {@code null}
*/
String getTenantIdentifier();
/**
* A UUID associated with each Session. Useful mainly for logging.
*
* @return The UUID
* Obtain a {@link UUID} which uniquely identifies this session.
* <p>
* The UUID is useful mainly for logging.
*/
UUID getSessionIdentifier();
/**
* Returns this object, fulfilling the contract of {@link WrapperOptions}.
*/
@Override
default SharedSessionContractImplementor getSession() {
return this;
}
/**
* A "token" that is unique to this Session.
*
* @return The token
* Obtain a "token" which uniquely identifies this session.
*/
default Object getSessionToken() {
return this;
}
/**
* Checks whether the session is closed. Provided separately from
* {@link #isOpen()} as this method does not attempt any JTA synchronization
* registration, whereas {@link #isOpen()} does; which makes this one
* nicer to use for most internal purposes.
* Determines whether the session is closed.
* <p>
* @apiNote Provided separately from {@link #isOpen()} as this method
* does not attempt any JTA synchronization registration,
* whereas {@link #isOpen()} does. This one is better for most
* internal purposes.
*
* @return {@code true} if the session is closed; {@code false} otherwise.
*/
boolean isClosed();
/**
* Checks whether the session is open or is waiting for auto-close
* Determines whether the session is open or is waiting for auto-close.
*
* @return {@code true} if the session is closed or if it's waiting for auto-close; {@code false} otherwise.
* @return {@code true} if the session is closed, or if it's waiting
* for auto-close; {@code false} otherwise.
*/
default boolean isOpenOrWaitingForAutoClose() {
return !isClosed();
}
/**
* Performs a check whether the Session is open, and if not:<ul>
* <li>marks current transaction (if one) for rollback only</li>
* <li>throws an IllegalStateException (JPA defines the exception type)</li>
* Check whether the session is open, and if not:
* <ul>
* <li>mark the current transaction, if any, for rollback only,
* and</li>
* <li>throw an {@code IllegalStateException}.
* (JPA specifies this exception type.)</li>
* </ul>
*/
default void checkOpen() {
@ -165,9 +187,12 @@ public interface SharedSessionContractImplementor
}
/**
* Performs a check whether the Session is open, and if not:<ul>
* <li>if {@code markForRollbackIfClosed} is true, marks current transaction (if one) for rollback only</li>
* <li>throws an IllegalStateException (JPA defines the exception type)</li>
* Check whether the session is open, and if not:
* <ul>
* <li>if {@code markForRollbackIfClosed = true}, mark the
* current transaction, if any, for rollback only, and
* <li>throw an {@code IllegalStateException}.
* (JPA specifies this exception type.)
* </ul>
*/
void checkOpen(boolean markForRollbackIfClosed);
@ -179,27 +204,31 @@ public interface SharedSessionContractImplementor
void prepareForQueryExecution(boolean requiresTxn);
/**
* Marks current transaction (if one) for rollback only
* Marks current transaction, if any, for rollback only.
*/
void markForRollbackOnly();
/**
* The current CacheTransactionContext associated with the Session. This may
* return {@code null} when the Session is not currently part of a transaction.
* The current {@link CacheTransactionSynchronization} associated
* with this session. This may be {@code null} if the session is not
* currently associated with an active transaction.
*/
CacheTransactionSynchronization getCacheTransactionSynchronization();
/**
* Does this {@code Session} have an active Hibernate transaction
* or is there a JTA transaction in progress?
* Does this session have an active Hibernate transaction, or is it
* associated with a JTA transaction currently in progress?
*/
boolean isTransactionInProgress();
/**
* Check if an active Transaction is necessary for the update operation to be executed.
* If an active Transaction is necessary but it is not then a TransactionRequiredException is raised.
* Check if an active {@link Transaction} is available before performing
* an update operation against the database.
* <p>
* If an active transaction is necessary, but no transaction is active,
* a {@link TransactionRequiredException} is raised.
*
* @param exceptionMessage the message to use for the TransactionRequiredException
* @param exceptionMessage the message to use for the {@link TransactionRequiredException}
*/
default void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
if ( !isTransactionInProgress() ) {
@ -208,16 +237,18 @@ public interface SharedSessionContractImplementor
}
/**
* Provides access to the underlying transaction or creates a new transaction if
* one does not already exist or is active. This is primarily for internal or
* integrator use.
* Retrieves the current {@link Transaction}, or creates a new transaction
* if there is no transaction active.
* <p>
* This method is primarily for internal or integrator use.
*
* @return the transaction
* @return the {@link Transaction}
*/
Transaction accessTransaction();
/**
* Hide the changing requirements of entity key creation
* Instantiate an {@link EntityKey} with the given id and for the
* entity represented by the given {@link EntityPersister}.
*
* @param id The entity id
* @param persister The entity persister
@ -227,48 +258,50 @@ public interface SharedSessionContractImplementor
EntityKey generateEntityKey(Object id, EntityPersister persister);
/**
* Retrieves the interceptor currently in use by this event source.
*
* @return The interceptor.
* Retrieves the {@link Interceptor} associated with this session.
*/
Interceptor getInterceptor();
/**
* Enable/disable automatic cache clearing from after transaction
* completion (for EJB3)
* Enable or disable automatic cache clearing from after transaction
* completion.
*
* @deprecated there's no good reason to expose this here
*/
@Deprecated(since = "6")
void setAutoClear(boolean enabled);
/**
* Initialize the collection (if not already initialized)
* Initialize the given collection (if not already initialized).
*/
void initializeCollection(PersistentCollection<?> collection, boolean writing)
throws HibernateException;
/**
* Load an instance without checking if it was deleted.
* <p>
* When {@code nullable} is disabled this method may create a new proxy or
* return an existing proxy; if it does not exist, throw an exception.
* <p>
* When {@code nullable} is enabled, the method does not create new proxies
* (but might return an existing proxy); if it does not exist, return
* {@code null}.
* <p>
* When {@code eager} is enabled, the object is eagerly fetched
* Obtain an entity instance with the given id, without checking if it was
* deleted or scheduled for deletion.
* <ul>
* <li>When {@code nullable = false}, this method may create a new proxy or
* return an existing proxy; if it does not exist, an exception is thrown.
* <li>When {@code nullable = true}, the method does not create new proxies,
* though it might return an existing proxy; if it does not exist, a
* {@code null} value is returned.
* </ul>
* When {@code eager = true}, the object is eagerly fetched from the database.
*/
Object internalLoad(String entityName, Object id, boolean eager, boolean nullable)
throws HibernateException;
/**
* Load an instance immediately. This method is only called when lazily initializing a proxy.
* Load an instance immediately.
* This method is only called when lazily initializing a proxy.
* Do not return the proxy.
*/
Object immediateLoad(String entityName, Object id) throws HibernateException;
/**
* Get the {@code EntityPersister} for any instance
* Get the {@link EntityPersister} for the given entity instance.
*
* @param entityName optional entity name
* @param object the entity instance
@ -276,43 +309,60 @@ public interface SharedSessionContractImplementor
EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException;
/**
* Get the entity instance associated with the given {@code Key},
* calling the Interceptor if necessary
* Get the entity instance associated with the given {@link EntityKey},
* calling the {@link Interceptor} if necessary.
*/
Object getEntityUsingInterceptor(EntityKey key) throws HibernateException;
/**
* Return the identifier of the persistent object, or null if
* not associated with the session
* Return the identifier of the persistent object, or null if it is
* not associated with this session.
*/
Object getContextEntityIdentifier(Object object);
/**
* The best guess entity name for an entity not in an association
* Obtain the best estimate of the entity name of the given entity
* instance, which is not involved in an association, by also
* considering information held in the proxy, and whether the object
* is already associated with this session.
*/
String bestGuessEntityName(Object object);
/**
* The guessed entity name for an entity not in an association
* Obtain an estimate of the entity name of the given entity instance,
* which is not involved in an association, using only the
* {@link org.hibernate.EntityNameResolver}.
*/
String guessEntityName(Object entity) throws HibernateException;
/**
* Instantiate the entity class, initializing with the given identifier
* Instantiate the entity class, initializing with the given identifier.
*/
Object instantiate(String entityName, Object id) throws HibernateException;
/**
* Instantiate the entity class of an EntityPersister, initializing with the given identifier.
* This is more efficient than {@link #instantiate(String, Object)} but not always
* interchangeable: a single persister might be responsible for multiple types.
* Instantiate the entity class of the given {@link EntityPersister},
* initializing the new instance with the given identifier.
* <p>
* This is more efficient than {@link #instantiate(String, Object)},
* but not always interchangeable, since a single persister might be
* responsible for multiple types.
*/
Object instantiate(EntityPersister persister, Object id) throws HibernateException;
/**
* Are entities and proxies loaded by this session read-only by default?
*/
boolean isDefaultReadOnly();
/**
* Get the current {@link CacheMode} for this session.
*/
CacheMode getCacheMode();
/**
* Set the current {@link CacheMode} for this session.
*/
void setCacheMode(CacheMode cm);
void setCriteriaCopyTreeEnabled(boolean jpaCriteriaCopyComplianceEnabled);
@ -320,73 +370,121 @@ public interface SharedSessionContractImplementor
boolean isCriteriaCopyTreeEnabled();
/**
* Get the flush mode for this session.
* Get the current {@link FlushModeType} for this session.
* <p>
* For users of the Hibernate native APIs, we've had to rename this method
* as defined by Hibernate historically because the JPA contract defines a method of the same
* name, but returning the JPA {@link FlushModeType} rather than Hibernate's {@link FlushMode}. For
* the former behavior, use {@link #getHibernateFlushMode()} instead.
* name, but returning the JPA {@link FlushModeType} rather than Hibernate's {@link FlushMode}.
* For the former behavior, use {@link #getHibernateFlushMode()} instead.
*
* @return The FlushModeType in effect for this Session.
* @return The {@link FlushModeType} in effect for this Session.
*
* @deprecated there's no good reason to expose this here
*/
@Deprecated(since = "6")
FlushModeType getFlushMode();
/**
* Set the flush mode for this session.
* Set the current {@link FlushMode} for this session.
* <p>
* The flush mode determines the points at which the session is flushed.
* <i>Flushing</i> is the process of synchronizing the underlying persistent
* store with persistable state held in memory.
* <p>
* For a logically "read only" session, it is reasonable to set the session's
* flush mode to {@link FlushMode#MANUAL} at the start of the session (in
* order to achieve some extra performance).
* For a logically "read-only" session, it's reasonable to set the session
* flush mode to {@link FlushMode#MANUAL} at the start of the session
* (in order skip some work and gain some extra performance).
*
* @param flushMode the new flush mode
*/
void setHibernateFlushMode(FlushMode flushMode);
/**
* Get the current flush mode for this session.
* Get the current {@link FlushMode} for this session.
*
* @return The flush mode
*/
FlushMode getHibernateFlushMode();
/**
* Flush this session.
*/
void flush();
boolean isEventSource();
/**
* Determines if this session implements {@link EventSource}.
* <p>
* Only stateful session are sources of events. If this object is
* a stateless session, this method return {@code false}.
*/
default boolean isEventSource() {
return false;
}
EventSource asEventSource();
/**
* Cast this session to {@link EventSource} if possible.
* <p>
* Only stateful session are sources of events. If this object is
* a stateless session, this method throws.
*
* @throws ClassCastException if the cast is not possible
*/
default EventSource asEventSource() {
throw new ClassCastException( "session is not an EventSource" );
}
/**
* Called after each operation on a {@link org.hibernate.ScrollableResults},
* providing an opportunity for a stateless session to clear its
* temporary persistence context. For a stateful session, this method
* does nothing.
*/
void afterScrollOperation();
/**
* Should this session be automatically closed after the current
* transaction completes?
*
* @deprecated there's no reason to expose this here
*/
@Deprecated(since = "6")
boolean shouldAutoClose();
/**
* Is auto-close at transaction completion enabled?
*
* @see org.hibernate.cfg.AvailableSettings#AUTO_CLOSE_SESSION
* @see SessionFactoryOptions#isAutoCloseSessionEnabled()
*
* @deprecated there's no reason to expose this here
*/
@Deprecated(since = "6")
boolean isAutoCloseSessionEnabled();
/**
* Get the load query influencers associated with this session.
* Get the {@link LoadQueryInfluencers} associated with this session.
*
* @return the load query influencers associated with this session;
* @return the {@link LoadQueryInfluencers} associated with this session;
* should never be null.
*/
LoadQueryInfluencers getLoadQueryInfluencers();
/**
* The converter associated to a Session might be lazily initialized: only invoke
* this getter when there is actual need to use it.
* Obtain an {@link ExceptionConverter} for reporting an error.
* <p>
* The converter associated to a session might be lazily initialized,
* so only invoke this getter when there's an actual need to use it.
*
* @return the ExceptionConverter for this Session.
*/
ExceptionConverter getExceptionConverter();
/**
* Get the currently configured JDBC batch size either at the Session-level or SessionFactory-level.
* Get the currently configured JDBC batch size, which might have
* been specified at either the session or factory level.
*
* If the Session-level JDBC batch size was not configured, return the SessionFactory-level one.
*
* @return Session-level or SessionFactory-level JDBC batch size.
* @return the session-level JDBC batch size is set, or the
* factory-level setting otherwise
*
* @since 5.2
*
@ -401,16 +499,15 @@ public interface SharedSessionContractImplementor
}
/**
* This is similar to {@link #getPersistenceContext()}, with
* two main differences:
* a) this version performs better as
* it allows for inlining and probably better prediction
* b) see SessionImpl{@link #getPersistenceContext()} : it
* does some checks on the current state of the Session.
* Similar to {@link #getPersistenceContext()}, with two differences:
* <ol>
* <li>this version performs better as it allows for inlining
* and probably better prediction, and
* <li>it skips some checks of the current state of the session.
* </ol>
* Choose wisely: performance is important, but correctness comes first.
*
* Choose wisely: performance is important, correctness comes first.
*
* @return the PersistenceContext associated to this session.
* @return the {@link PersistenceContext} associated to this session.
*/
PersistenceContext getPersistenceContextInternal();
@ -424,45 +521,63 @@ public interface SharedSessionContractImplementor
*/
boolean autoFlushIfRequired(Set<String> querySpaces) throws HibernateException;
/**
* Are we currently enforcing a {@linkplain GraphSemantic#FETCH fetch graph}?
*
* @deprecated this is not used anywhere
*/
@Deprecated(since = "6", forRemoval = true)
default boolean isEnforcingFetchGraph() {
return false;
}
/**
* Enable or disable {@linkplain GraphSemantic#FETCH fetch graph} enforcement.
*
* @deprecated this is not used anywhere
*/
@Deprecated(since = "6", forRemoval = true)
default void setEnforcingFetchGraph(boolean enforcingFetchGraph) {
}
/**
* Check if there is a Hibernate or JTA transaction in progress and,
* if there is not, flush if necessary, make sure the connection has
* been committed (if it is not in autocommit mode) and run the after
* completion processing
* if there is not, flush if necessary, making sure that the connection
* has been committed (if it is not in autocommit mode), and finally
* run the after completion processing.
*
* @param success Was the operation a success
* @param success {@code true} if the operation a success
*/
void afterOperation(boolean success);
/**
* If this can be casted to a @{@link SessionImplementor},
* you'll get this returned after an efficient cast.
* @throws ClassCastException if this is not compatible!
* Cast this object to {@link SessionImplementor}, if possible.
*
* @throws ClassCastException if the cast is not possible
*/
default SessionImplementor asSessionImplementor() {
throw new ClassCastException();
throw new ClassCastException( "session is not a SessionImplementor" );
}
/**
* Does this object implement {@link SessionImplementor}?
*/
default boolean isSessionImplementor() {
return false;
}
/**
* If this can be casted to a @{@link StatelessSession},
* you'll get this returned after an efficient cast.
* @throws ClassCastException if this is not compatible!
* Cast this object to {@link StatelessSession}, if possible.
*
* @throws ClassCastException if the cast is not possible
*/
default StatelessSession asStatelessSession() {
throw new ClassCastException();
throw new ClassCastException( "session is not a StatelessSession" );
}
/**
* Does this object implement {@link StatelessSession}?
*/
default boolean isStatelessSession() {
return false;
}

View File

@ -18,5 +18,9 @@ public enum Status {
DELETED,
GONE,
LOADING,
SAVING
SAVING;
public boolean isDeletedOrGone() {
return this == DELETED || this == GONE;
}
}

View File

@ -210,7 +210,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
EntityEntry entityEntry) {
LOG.trace( "Deleting a persistent instance" );
final EventSource source = event.getSession();
if ( entityEntry.getStatus() == Status.DELETED || entityEntry.getStatus() == Status.GONE
if ( entityEntry.getStatus().isDeletedOrGone()
|| source.getPersistenceContextInternal()
.containsDeletedUnloadedEntityKey( entityEntry.getEntityKey() ) ) {
LOG.trace( "Object was already deleted" );

View File

@ -443,8 +443,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
}
private static boolean wasDeleted(PersistenceContext persistenceContext, Object existing) {
final Status status = persistenceContext.getEntry( existing ).getStatus();
return status == Status.DELETED || status == Status.GONE;
return persistenceContext.getEntry( existing ).getStatus().isDeletedOrGone();
}
private static Object createProxy(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) {

View File

@ -41,11 +41,9 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.transaction.internal.TransactionImpl;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.id.uuid.StandardRandomStrategy;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCall;
@ -62,12 +60,10 @@ import org.hibernate.query.UnknownNamedQueryException;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.query.criteria.JpaCriteriaInsertSelect;
import org.hibernate.query.hql.spi.SqmQueryImplementor;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.spi.HqlInterpretation;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.sql.internal.NativeQueryImpl;
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
@ -101,22 +97,19 @@ import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import static java.lang.Boolean.TRUE;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.jpa.internal.util.FlushModeTypeHelper.getFlushModeType;
/**
* Base class for implementations of {@link org.hibernate.SharedSessionContract} and
* {@link SharedSessionContractImplementor}. Intended for concrete implementations of
* {@link org.hibernate.Session} and {@link org.hibernate.StatelessSession}.
* <p>
* NOTE: This implementation defines access to a number of instance state values
* in a manner that is not exactly concurrent-access safe. However, a Session/EntityManager
* is never intended to be used concurrently; therefore the condition is not expected
* and so a more synchronized/concurrency-safe is not defined to be as negligent
* (performance-wise) as possible. Some of these methods include:<ul>
* <li>{@link #getEventListenerManager()}</li>
* <li>{@link #getJdbcConnectionAccess()}</li>
* <li>{@link #getJdbcServices()}</li>
* <li>{@link #getTransaction()} (and therefore related methods such as {@link #beginTransaction()}, etc)</li>
* </ul>
* @implNote A {@code Session} or JPA {@code EntityManager} is a single-threaded object,
* which may not be called concurrently. Therefore, this implementation defines
* access to a number of instance state values in a manner that is not exactly
* thread-safe.
*
* @see SessionImpl
* @see StatelessSessionImpl
@ -127,8 +120,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( SessionImpl.class );
private transient SessionFactoryImpl factory;
private final String tenantIdentifier;
protected transient FastSessionServices fastSessionServices;
private UUID sessionIdentifier;
private Object sessionToken;
@ -140,101 +133,115 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
private transient TransactionCoordinator transactionCoordinator;
private transient CacheTransactionSynchronization cacheTransactionSync;
private final boolean autoJoinTransactions;
private final boolean isTransactionCoordinatorShared;
private final Interceptor interceptor;
private final TimeZone jdbcTimeZone;
private FlushMode flushMode;
private boolean autoJoinTransactions;
private final PhysicalConnectionHandlingMode connectionHandlingMode;
private final Interceptor interceptor;
private final String tenantIdentifier;
private final TimeZone jdbcTimeZone;
// mutable state
private FlushMode flushMode;
private CacheMode cacheMode;
private Integer jdbcBatchSize;
private boolean criteriaCopyTreeEnabled;
protected boolean closed;
protected boolean waitingForAutoClose;
// transient & non-final for Serialization purposes - ugh
private transient SessionEventListenerManagerImpl sessionEventsManager;
// transient & non-final for serialization purposes
private transient SessionEventListenerManager sessionEventsManager;
private transient EntityNameResolver entityNameResolver;
private Integer jdbcBatchSize;
//Lazily initialized
private transient ExceptionConverter exceptionConverter;
public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreationOptions options) {
this.factory = factory;
this.fastSessionServices = factory.getFastSessionServices();
this.cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this );
fastSessionServices = factory.getFastSessionServices();
cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this );
flushMode = options.getInitialSessionFlushMode();
tenantIdentifier = getTenantId( factory, options );
interceptor = interpret( options.getInterceptor() );
jdbcTimeZone = options.getJdbcTimeZone();
sessionEventsManager = createSessionEventsManager(options);
entityNameResolver = new CoordinatingEntityNameResolver( factory, interceptor );
setCriteriaCopyTreeEnabled( factory.getSessionFactoryOptions().isCriteriaCopyTreeEnabled() );
this.flushMode = options.getInitialSessionFlushMode();
this.tenantIdentifier = options.getTenantIdentifier();
if ( factory.getSessionFactoryOptions().isMultiTenancyEnabled() && tenantIdentifier == null ) {
throw new HibernateException( "SessionFactory configured for multi-tenancy, but no tenant identifier specified" );
}
this.interceptor = interpret( options.getInterceptor() );
this.jdbcTimeZone = options.getJdbcTimeZone();
final List<SessionEventListener> customSessionEventListener = options.getCustomSessionEventListener();
if ( customSessionEventListener == null ) {
sessionEventsManager = new SessionEventListenerManagerImpl( fastSessionServices.defaultSessionEventListeners.buildBaseline() );
}
else {
sessionEventsManager = new SessionEventListenerManagerImpl( customSessionEventListener.toArray( new SessionEventListener[0] ) );
}
this.entityNameResolver = new CoordinatingEntityNameResolver( factory, interceptor );
final StatementInspector statementInspector = interpret( options.getStatementInspector() );
if ( options instanceof SharedSessionCreationOptions && ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared() ) {
isTransactionCoordinatorShared = isTransactionCoordinatorShared( options );
if ( isTransactionCoordinatorShared ) {
final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options;
if ( options.getConnection() != null ) {
throw new SessionException( "Cannot simultaneously share transaction context and specify connection" );
}
this.isTransactionCoordinatorShared = true;
final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options;
this.transactionCoordinator = sharedOptions.getTransactionCoordinator();
this.jdbcCoordinator = sharedOptions.getJdbcCoordinator();
transactionCoordinator = sharedOptions.getTransactionCoordinator();
jdbcCoordinator = sharedOptions.getJdbcCoordinator();
// todo : "wrap" the transaction to no-op commit/rollback attempts?
this.currentHibernateTransaction = sharedOptions.getTransaction();
currentHibernateTransaction = sharedOptions.getTransaction();
connectionHandlingMode = jdbcCoordinator.getLogicalConnection().getConnectionHandlingMode();
autoJoinTransactions = false;
jdbcSessionContext = createJdbcSessionContext( statementInspector );
logInconsistentOptions( sharedOptions );
addSharedSessionTransactionObserver( transactionCoordinator );
}
else {
autoJoinTransactions = options.shouldAutoJoinTransactions();
connectionHandlingMode = options.getPhysicalConnectionHandlingMode();
jdbcSessionContext = createJdbcSessionContext( statementInspector );
// This must happen *after* the JdbcSessionContext was initialized,
// because some calls retrieve this context indirectly via Session getters.
jdbcCoordinator = createJdbcCoordinator( options );
transactionCoordinator = fastSessionServices.transactionCoordinatorBuilder
.buildTransactionCoordinator( jdbcCoordinator, this );
}
}
private static boolean isTransactionCoordinatorShared(SessionCreationOptions options) {
return options instanceof SharedSessionCreationOptions
&& ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared();
}
private void logInconsistentOptions(SharedSessionCreationOptions sharedOptions) {
if ( sharedOptions.shouldAutoJoinTransactions() ) {
log.debug(
"Session creation specified 'autoJoinTransactions', which is invalid in conjunction " +
"with sharing JDBC connection between sessions; ignoring"
);
autoJoinTransactions = false;
}
this.connectionHandlingMode = this.jdbcCoordinator.getLogicalConnection().getConnectionHandlingMode();
if ( sharedOptions.getPhysicalConnectionHandlingMode() != this.connectionHandlingMode ) {
if ( sharedOptions.getPhysicalConnectionHandlingMode() != connectionHandlingMode ) {
log.debug(
"Session creation specified 'PhysicalConnectionHandlingMode' which is invalid in conjunction " +
"with sharing JDBC connection between sessions; ignoring"
);
}
this.jdbcSessionContext = new JdbcSessionContextImpl( this, statementInspector,
connectionHandlingMode, fastSessionServices );
addSharedSessionTransactionObserver( transactionCoordinator );
}
else {
this.isTransactionCoordinatorShared = false;
this.autoJoinTransactions = options.shouldAutoJoinTransactions();
this.connectionHandlingMode = options.getPhysicalConnectionHandlingMode();
this.jdbcSessionContext = new JdbcSessionContextImpl( this, statementInspector,
connectionHandlingMode, fastSessionServices );
// This must happen *after* the JdbcSessionContext was initialized,
// because some of the calls below retrieve this context indirectly through Session getters.
this.jdbcCoordinator = new JdbcCoordinatorImpl( options.getConnection(), this, fastSessionServices.jdbcServices );
this.transactionCoordinator = fastSessionServices.transactionCoordinatorBuilder.buildTransactionCoordinator( jdbcCoordinator, this );
private JdbcCoordinatorImpl createJdbcCoordinator(SessionCreationOptions options) {
return new JdbcCoordinatorImpl( options.getConnection(), this, fastSessionServices.jdbcServices );
}
private JdbcSessionContextImpl createJdbcSessionContext(StatementInspector statementInspector) {
return new JdbcSessionContextImpl(this, statementInspector, connectionHandlingMode, fastSessionServices );
}
private String getTenantId( SessionFactoryImpl factory, SessionCreationOptions options ) {
final String tenantIdentifier = options.getTenantIdentifier();
if ( factory.getSessionFactoryOptions().isMultiTenancyEnabled() && tenantIdentifier == null ) {
throw new HibernateException( "SessionFactory configured for multi-tenancy, but no tenant identifier specified" );
}
return tenantIdentifier;
}
private SessionEventListenerManager createSessionEventsManager(SessionCreationOptions options) {
final List<SessionEventListener> customSessionEventListener = options.getCustomSessionEventListener();
return customSessionEventListener == null
? new SessionEventListenerManagerImpl( fastSessionServices.defaultSessionEventListeners.buildBaseline() )
: new SessionEventListenerManagerImpl( customSessionEventListener.toArray( new SessionEventListener[0] ) );
}
/**
@ -244,7 +251,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
*/
@Override
public Integer getConfiguredJdbcBatchSize() {
final Integer sessionJdbcBatchSize = this.jdbcBatchSize;
final Integer sessionJdbcBatchSize = jdbcBatchSize;
return sessionJdbcBatchSize == null ?
fastSessionServices.defaultJdbcBatchSize :
sessionJdbcBatchSize;
@ -301,7 +308,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public JdbcSessionContext getJdbcSessionContext() {
return this.jdbcSessionContext;
return jdbcSessionContext;
}
public EntityNameResolver getEntityNameResolver() {
@ -315,9 +322,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public UUID getSessionIdentifier() {
if ( this.sessionIdentifier == null ) {
if ( sessionIdentifier == null ) {
//Lazily initialized: otherwise all the UUID generations will cause significant amount of contention.
this.sessionIdentifier = StandardRandomStrategy.INSTANCE.generateUUID( null );
sessionIdentifier = StandardRandomStrategy.INSTANCE.generateUUID( null );
}
return sessionIdentifier;
}
@ -464,21 +471,18 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public Transaction accessTransaction() {
if ( this.currentHibernateTransaction == null ) {
this.currentHibernateTransaction = new TransactionImpl(
getTransactionCoordinator(),
this
);
if ( currentHibernateTransaction == null ) {
currentHibernateTransaction = new TransactionImpl( getTransactionCoordinator(), this );
}
if ( !isClosed() || ( waitingForAutoClose && factory.isOpen() ) ) {
if ( !isClosed() || waitingForAutoClose && factory.isOpen() ) {
getTransactionCoordinator().pulse();
}
return this.currentHibernateTransaction;
return currentHibernateTransaction;
}
@Override
public void startTransactionBoundary() {
this.getCacheTransactionSynchronization().transactionJoined();
getCacheTransactionSynchronization().transactionJoined();
}
@Override
@ -499,10 +503,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public Transaction beginTransaction() {
checkOpen();
Transaction result = getTransaction();
final Transaction result = getTransaction();
result.begin();
return result;
}
@ -527,7 +529,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
protected void delayedAfterCompletion() {
if ( transactionCoordinator instanceof JtaTransactionCoordinatorImpl ) {
( (JtaTransactionCoordinatorImpl) transactionCoordinator ).getSynchronizationCallbackCoordinator()
( (JtaTransactionCoordinatorImpl) transactionCoordinator )
.getSynchronizationCallbackCoordinator()
.processAnyDelayedAfterCompletion();
}
}
@ -613,7 +616,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public FlushModeType getFlushMode() {
checkOpen();
return FlushModeTypeHelper.getFlushModeType( this.flushMode );
return getFlushModeType( flushMode );
}
@Override
@ -638,7 +641,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public void setCriteriaCopyTreeEnabled(boolean jpaCriteriaCopyComplianceEnabled) {
this.criteriaCopyTreeEnabled = jpaCriteriaCopyComplianceEnabled;
criteriaCopyTreeEnabled = jpaCriteriaCopyComplianceEnabled;
}
@Override
@ -656,35 +659,52 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public SelectionQuery<?> createSelectionQuery(String hqlString) {
return internalCreateSelectionQuery( hqlString, null );
return interpretAndCreateSelectionQuery( hqlString, null );
}
private <R> SelectionQuery<R> internalCreateSelectionQuery(String hqlString, Class<R> expectedResultType) {
private <R> SelectionQuery<R> interpretAndCreateSelectionQuery(String hql, Class<R> resultType) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
try {
final QueryEngine queryEngine = getFactory().getQueryEngine();
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
hqlString,
expectedResultType,
(s) -> queryEngine.getHqlTranslator().translate( hqlString, expectedResultType )
);
if ( !( hqlInterpretation.getSqmStatement() instanceof SqmSelectStatement ) ) {
throw new IllegalSelectQueryException( "Expecting a selection query, but found `" + hqlString + "`", hqlString );
final HqlInterpretation interpretation = interpretHql( hql, resultType );
checkSelectionQuery( hql, interpretation );
return createSelectionQuery( hql, resultType, interpretation);
}
catch ( RuntimeException e ) {
markForRollbackOnly();
throw e;
}
}
final SqmSelectionQueryImpl<?> query = new SqmSelectionQueryImpl<>(
hqlString,
hqlInterpretation,
expectedResultType,
this
);
private <R> SelectionQuery<R> createSelectionQuery(String hql, Class<R> resultType, HqlInterpretation interpretation) {
final SqmSelectionQueryImpl<R> query = new SqmSelectionQueryImpl<>( hql, interpretation, resultType, this );
if ( resultType != null ) {
checkResultType( resultType, query );
}
query.setComment( hql );
applyQuerySettingsAndHints( query );
return query;
}
if ( expectedResultType != null ) {
private <R> HqlInterpretation interpretHql(String hql, Class<R> resultType) {
final QueryEngine queryEngine = getFactory().getQueryEngine();
return queryEngine.getInterpretationCache()
.resolveHqlInterpretation(
hql,
resultType,
s -> queryEngine.getHqlTranslator().translate( hql, resultType )
);
}
private static void checkSelectionQuery(String hql, HqlInterpretation hqlInterpretation) {
if ( !( hqlInterpretation.getSqmStatement() instanceof SqmSelectStatement ) ) {
throw new IllegalSelectQueryException( "Expecting a selection query, but found `" + hql + "`", hql);
}
}
private static <R> void checkResultType(Class<R> expectedResultType, SqmSelectionQueryImpl<?> query) {
final Class<?> resultType = query.getResultType();
if ( !expectedResultType.isAssignableFrom( resultType ) ) {
throw new QueryTypeMismatchException(
@ -698,21 +718,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
}
query.setComment( hqlString );
applyQuerySettingsAndHints( query );
//noinspection unchecked
return (SelectionQuery<R>) query;
}
catch (RuntimeException e) {
markForRollbackOnly();
throw e;
}
}
@Override
public <R> SelectionQuery<R> createSelectionQuery(String hqlString, Class<R> expectedResultType) {
return internalCreateSelectionQuery( hqlString, expectedResultType );
return interpretAndCreateSelectionQuery( hqlString, expectedResultType );
}
@Override
@ -728,20 +736,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
delayedAfterCompletion();
try {
final QueryEngine queryEngine = getFactory().getQueryEngine();
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
final QuerySqmImpl<T> query = new QuerySqmImpl<>(
queryString,
interpretationCache.resolveHqlInterpretation(
queryString,
expectedResultType,
s -> queryEngine.getHqlTranslator().translate( queryString, expectedResultType )
),
expectedResultType,
this
);
final HqlInterpretation interpretation = interpretHql( queryString, expectedResultType );
final QuerySqmImpl<T> query = new QuerySqmImpl<>( queryString, interpretation, expectedResultType, this );
applyQuerySettingsAndHints( query );
query.setComment( queryString );
@ -764,8 +760,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
delayedAfterCompletion();
try {
NativeQueryImpl query = new NativeQueryImpl<>(sqlString, this);
if ( StringHelper.isEmpty( query.getComment() ) ) {
final NativeQueryImpl query = new NativeQueryImpl<>( sqlString, this );
if ( isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native SQL query" );
}
applyQuerySettingsAndHints( query );
@ -783,21 +779,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
delayedAfterCompletion();
try {
if ( StringHelper.isNotEmpty(resultSetMappingName) ) {
final NamedResultSetMappingMemento resultSetMappingMemento = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getResultSetMappingMemento(resultSetMappingName);
if ( resultSetMappingMemento == null ) {
throw new HibernateException( "Could not resolve specified result-set mapping name : "
+ resultSetMappingName);
}
return new NativeQueryImpl<>(sqlString, resultSetMappingMemento, this);
}
else {
return new NativeQueryImpl<>(sqlString, this);
}
return isNotEmpty( resultSetMappingName )
? new NativeQueryImpl<>( sqlString, getResultSetMappingMemento( resultSetMappingName ), this )
: new NativeQueryImpl<>( sqlString, this );
//TODO: why no applyQuerySettingsAndHints( query ); ???
}
catch ( RuntimeException he ) {
@ -805,11 +789,21 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
}
private NamedResultSetMappingMemento getResultSetMappingMemento(String resultSetMappingName) {
final NamedResultSetMappingMemento resultSetMappingMemento = getFactory().getQueryEngine()
.getNamedObjectRepository().getResultSetMappingMemento( resultSetMappingName );
if ( resultSetMappingMemento == null ) {
throw new HibernateException( "Could not resolve specified result-set mapping name : "
+ resultSetMappingName);
}
return resultSetMappingMemento;
}
@Override @SuppressWarnings({"rawtypes", "unchecked"})
//note: we're doing something a bit funny here to work around
// the clashing signatures declared by the supertypes
public NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass) {
NativeQueryImpl query = createNativeQuery( sqlString );
final NativeQueryImpl query = createNativeQuery( sqlString );
if ( Tuple.class.equals( resultClass ) ) {
query.setTupleTransformer( new NativeQueryTupleTransformer() );
}
@ -825,7 +819,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public <T> NativeQueryImplementor<T> createNativeQuery(String sqlString, Class<T> resultClass, String tableAlias) {
@SuppressWarnings("unchecked")
NativeQueryImplementor<T> query = createNativeQuery( sqlString );
final NativeQueryImplementor<T> query = createNativeQuery( sqlString );
if ( getFactory().getMappingMetamodel().isEntityClass( resultClass ) ) {
query.addEntity( tableAlias, resultClass.getName(), LockMode.READ );
}
@ -870,32 +864,23 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public <R> SelectionQuery<R> createNamedSelectionQuery(String queryName, Class<R> expectedResultType) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
return buildNamedQuery(
queryName,
memento -> createNamedSqmSelectionQuery( memento, expectedResultType ),
memento -> createNamedNativeSelectionQuery( memento, expectedResultType )
);
}
// this method can be called for either a named HQL query or a named native query
// first see if it is a named HQL query
final NamedSqmQueryMemento namedHqlDescriptor = getFactory().getQueryEngine()
private NamedSqmQueryMemento getSqmQueryMemento(String queryName) {
return getFactory().getQueryEngine()
.getNamedObjectRepository()
.getSqmQueryMemento( queryName );
if ( namedHqlDescriptor != null ) {
return createNamedSqmSelectionQuery( namedHqlDescriptor, expectedResultType );
}
// otherwise, see if it is a named native query
final NamedNativeQueryMemento namedNativeDescriptor = getFactory().getQueryEngine()
private NamedNativeQueryMemento getNativeQueryMemento(String queryName) {
return getFactory().getQueryEngine()
.getNamedObjectRepository()
.getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
return createNamedNativeSelectionQuery( namedNativeDescriptor, expectedResultType );
}
throw new UnknownNamedQueryException( queryName );
}
private <R> SelectionQuery<R> createNamedNativeSelectionQuery(
@ -915,79 +900,73 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
NamedSqmQueryMemento memento,
Class<R> expectedResultType) {
final SqmSelectionQuery<R> selectionQuery = memento.toSelectionQuery( expectedResultType, this );
if ( StringHelper.isEmpty( memento.getComment() ) ) {
if ( isEmpty( memento.getComment() ) ) {
selectionQuery.setComment( "Named query : " + memento.getRegistrationName() );
}
else {
selectionQuery.setComment( memento.getComment() );
}
applyQuerySettingsAndHints( selectionQuery );
if ( memento.getLockOptions() != null ) {
selectionQuery.getLockOptions().overlay( memento.getLockOptions() );
}
return selectionQuery;
}
@Override
public void doWork(final Work work) throws HibernateException {
WorkExecutorVisitable<Void> realWork = (workExecutor, connection) -> {
doWork( (workExecutor, connection) -> {
workExecutor.executeWork( work, connection );
return null;
};
doWork( realWork );
} );
}
@Override
public <T> T doReturningWork(final ReturningWork<T> work) throws HibernateException {
WorkExecutorVisitable<T> realWork = (workExecutor, connection) -> workExecutor.executeReturningWork(
work,
connection
);
return doWork( realWork );
return doWork( (workExecutor, connection) -> workExecutor.executeReturningWork( work, connection ) );
}
private <T> T doWork(WorkExecutorVisitable<T> work) throws HibernateException {
return getJdbcCoordinator().coordinateWork( work );
}
@SuppressWarnings({"rawtypes","unchecked"})
protected void applyQuerySettingsAndHints(SelectionQuery<?> query) {
}
protected void applyQuerySettingsAndHints(Query<?> query) {
}
protected <Q> Q buildNamedQuery(
String queryName,
Function<NamedSqmQueryMemento, Q> sqlCreator,
Function<NamedNativeQueryMemento, Q> nativeCreator) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
// this method can be called for either a named HQL query or a named native query
// first see if it is a named HQL query
final NamedSqmQueryMemento namedSqmQueryMemento = getSqmQueryMemento( queryName );
if ( namedSqmQueryMemento != null ) {
return sqlCreator.apply( namedSqmQueryMemento );
}
// otherwise, see if it is a named native query
final NamedNativeQueryMemento namedNativeDescriptor = getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
return nativeCreator.apply( namedNativeDescriptor );
}
throw new UnknownNamedQueryException( queryName );
}
protected <T> QueryImplementor<T> buildNamedQuery(String queryName, Class<T> resultType) {
try {
return buildNamedQuery(
queryName,
(memento) -> {
final SqmQueryImplementor query = memento.toQuery( this, resultType );
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic query" );
}
applyQuerySettingsAndHints( query );
if ( memento.getLockOptions() != null ) {
query.setLockOptions( memento.getLockOptions() );
}
return query;
},
(memento) -> {
final NativeQueryImplementor query;
if ( resultType == null ) {
query = memento.toQuery( this );
}
else {
query = memento.toQuery( this, resultType );
}
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native-SQL query" );
}
applyQuerySettingsAndHints( query );
return query;
}
memento -> createSqmQueryImplementor( resultType, memento ),
memento -> createNativeQueryImplementor( resultType, memento )
);
}
catch ( UnknownNamedQueryException e ) {
@ -1004,78 +983,68 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
}
@SuppressWarnings("rawtypes")
protected QueryImplementor buildNamedQuery(
String queryName,
Function<NamedSqmQueryMemento, SqmQueryImplementor> namedSqmHandler,
Function<NamedNativeQueryMemento, NativeQueryImplementor> namedNativeHandler) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
// this method can be called for either a named HQL query or a named native query
// first see if it is a named HQL query
final NamedObjectRepository namedObjectRepository = getFactory().getQueryEngine()
.getNamedObjectRepository();
final NamedSqmQueryMemento namedSqmQueryMemento = namedObjectRepository.getSqmQueryMemento( queryName );
if ( namedSqmQueryMemento != null ) {
return namedSqmHandler.apply( namedSqmQueryMemento );
private <T> NativeQueryImplementor<T> createNativeQueryImplementor(Class<T> resultType, NamedNativeQueryMemento memento) {
final NativeQueryImplementor<T> query = resultType == null
? memento.toQuery(this )
: memento.toQuery(this, resultType );
if ( isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native-SQL query" );
}
applyQuerySettingsAndHints( query );
return query;
}
// otherwise, see if it is a named native query
final NamedNativeQueryMemento namedNativeDescriptor = namedObjectRepository
.getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
return namedNativeHandler.apply( namedNativeDescriptor );
private <T> SqmQueryImplementor<T> createSqmQueryImplementor(Class<T> resultType, NamedSqmQueryMemento memento) {
final SqmQueryImplementor<T> query = memento.toQuery( this, resultType );
if ( isEmpty( query.getComment() ) ) {
query.setComment( "dynamic query" );
}
throw new UnknownNamedQueryException( queryName );
applyQuerySettingsAndHints( query );
if ( memento.getLockOptions() != null ) {
query.setLockOptions( memento.getLockOptions() );
}
protected void applyQuerySettingsAndHints(SelectionQuery<?> query) {
}
protected void applyQuerySettingsAndHints(Query<?> query) {
return query;
}
@Override @SuppressWarnings("rawtypes")
public NativeQueryImplementor getNamedNativeQuery(String queryName) {
final NamedNativeQueryMemento namedNativeDescriptor = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getNativeQueryMemento( queryName );
final NamedNativeQueryMemento namedNativeDescriptor = getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
return namedNativeDescriptor.toQuery( this );
}
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + queryName + "]" ) );
else {
throw noQueryForNameException( queryName );
}
}
@Override @SuppressWarnings("rawtypes")
public NativeQueryImplementor getNamedNativeQuery(String queryName, String resultSetMapping) {
final NamedNativeQueryMemento namedNativeDescriptor = getFactory().getQueryEngine()
.getNamedObjectRepository()
.getNativeQueryMemento( queryName );
final NamedNativeQueryMemento namedNativeDescriptor = getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
return namedNativeDescriptor.toQuery( this, resultSetMapping );
}
else {
throw noQueryForNameException( queryName );
}
}
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + queryName + "]" ) );
private RuntimeException noQueryForNameException(String queryName) {
return getExceptionConverter()
.convert( new IllegalArgumentException( "No query defined for that name [" + queryName + "]" ) );
}
@Override
public MutationQuery createMutationQuery(String hqlString) {
final QueryImplementor<?> query = createQuery( hqlString );
final SqmStatement<?> sqmStatement = ( (SqmQueryImplementor<?>) query ).getSqmStatement();
checkMutationQuery( hqlString, sqmStatement );
return query;
}
private static void checkMutationQuery(String hqlString, SqmStatement<?> sqmStatement) {
if ( !( sqmStatement instanceof SqmDmlStatement ) ) {
throw new IllegalMutationQueryException( "Expecting a mutation query, but found `" + hqlString + "`" );
}
return query;
}
@Override
@ -1091,59 +1060,52 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
public MutationQuery createNamedMutationQuery(String queryName) {
return buildNamedQuery(
queryName,
(sqmMemento) -> {
final SqmQueryImplementor<?> query = sqmMemento.toQuery( this );
memento -> createSqmQueryImplementor( queryName, memento ),
memento -> createNativeQueryImplementor( queryName, memento )
);
}
private NativeQueryImplementor<?> createNativeQueryImplementor(String queryName, NamedNativeQueryMemento memento) {
final NativeQueryImplementor<?> query = memento.toQuery( this );
final Boolean isUnequivocallySelect = query.isSelectQuery();
if ( isUnequivocallySelect == TRUE ) {
throw new IllegalMutationQueryException(
"Expecting named native query (" + queryName + ") to be a mutation query, but found `"
+ memento.getSqlString() + "`"
);
}
if ( isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native-SQL query" );
}
applyQuerySettingsAndHints( query );
return query;
}
private SqmQueryImplementor<?> createSqmQueryImplementor(String queryName, NamedSqmQueryMemento memento) {
final SqmQueryImplementor<?> query = memento.toQuery( this );
final SqmStatement<?> sqmStatement = query.getSqmStatement();
if ( !( sqmStatement instanceof SqmDmlStatement ) ) {
throw new IllegalMutationQueryException(
"Expecting a named mutation query (" + queryName + "), but found a select statement"
);
}
if ( sqmMemento.getLockOptions() != null && ! sqmMemento.getLockOptions().isEmpty() ) {
if ( memento.getLockOptions() != null && ! memento.getLockOptions().isEmpty() ) {
throw new IllegalNamedQueryOptionsException(
"Named mutation query `" + queryName + "` specified lock-options"
);
}
if ( StringHelper.isEmpty( query.getComment() ) ) {
if ( isEmpty( query.getComment() ) ) {
query.setComment( "dynamic HQL query" );
}
applyQuerySettingsAndHints( query );
return query;
},
(nativeMemento) -> {
final NativeQueryImplementor<?> query = nativeMemento.toQuery( this );
final Boolean isUnequivocallySelect = query.isSelectQuery();
if ( isUnequivocallySelect == TRUE ) {
throw new IllegalMutationQueryException(
"Expecting named native query (" + queryName + ") to be a mutation query, but found `" + nativeMemento.getSqlString() + "`"
);
}
if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native-SQL query" );
}
applyQuerySettingsAndHints( query );
return query;
}
);
}
@Override
public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery) {
checkOpen();
try {
return new QuerySqmImpl<>(
(SqmUpdateStatement<?>) updateQuery,
null,
this
);
return new QuerySqmImpl<>( (SqmUpdateStatement<?>) updateQuery, null, this );
}
catch ( RuntimeException e ) {
throw getExceptionConverter().convert( e );
@ -1177,7 +1139,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
public ProcedureCall getNamedProcedureCall(String name) {
checkOpen();
final NamedCallableQueryMemento memento = factory.getQueryEngine().getNamedObjectRepository().getCallableQueryMemento( name );
final NamedCallableQueryMemento memento = factory.getQueryEngine()
.getNamedObjectRepository().getCallableQueryMemento( name );
if ( memento == null ) {
throw new IllegalArgumentException(
"Could not find named stored procedure call with that registration name : " + name
@ -1198,54 +1161,54 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
// dynamic ProcedureCall support
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureCall(String procedureName) {
checkOpen();
@SuppressWarnings("UnnecessaryLocalVariable")
final ProcedureCall procedureCall = new ProcedureCallImpl<>( this, procedureName );
// call.setComment( "Dynamic stored procedure call" );
return procedureCall;
}
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureCall(String procedureName, Class<?>... resultClasses) {
checkOpen();
@SuppressWarnings("UnnecessaryLocalVariable")
final ProcedureCall procedureCall = new ProcedureCallImpl<>( this, procedureName, resultClasses );
// call.setComment( "Dynamic stored procedure call" );
return procedureCall;
}
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) {
checkOpen();
@SuppressWarnings("UnnecessaryLocalVariable")
final ProcedureCall procedureCall = new ProcedureCallImpl<>( this, procedureName, resultSetMappings );
// call.setComment( "Dynamic stored procedure call" );
return procedureCall;
}
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureQuery(String procedureName) {
checkOpen();
@SuppressWarnings("UnnecessaryLocalVariable")
final ProcedureCall procedureCall = new ProcedureCallImpl<>( this, procedureName );
// call.setComment( "Dynamic stored procedure call" );
return procedureCall;
}
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureQuery(String procedureName, Class<?>... resultClasses) {
checkOpen();
@SuppressWarnings("UnnecessaryLocalVariable")
final ProcedureCall procedureCall = new ProcedureCallImpl<>( this, procedureName, resultClasses );
// call.setComment( "Dynamic stored procedure call" );
return procedureCall;
}
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
checkOpen();
@SuppressWarnings("UnnecessaryLocalVariable")
final ProcedureCall procedureCall = new ProcedureCallImpl<>( this, procedureName, resultSetMappings );
// call.setComment( "Dynamic stored procedure call" );
return procedureCall;
@ -1305,11 +1268,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
public QueryImplementor createQuery(@SuppressWarnings("rawtypes") CriteriaUpdate criteriaUpdate) {
checkOpen();
try {
return new QuerySqmImpl<>(
(SqmUpdateStatement<Void>) criteriaUpdate,
null,
this
);
return new QuerySqmImpl<>( (SqmUpdateStatement<Void>) criteriaUpdate, null, this );
}
catch (RuntimeException e) {
if ( getSessionFactory().getJpaMetamodel().getJpaCompliance().isJpaTransactionComplianceEnabled() ) {
@ -1323,11 +1282,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
public QueryImplementor createQuery(@SuppressWarnings("rawtypes") CriteriaDelete criteriaDelete) {
checkOpen();
try {
return new QuerySqmImpl<>(
(SqmDeleteStatement<Void>) criteriaDelete,
null,
this
);
return new QuerySqmImpl<>( (SqmDeleteStatement<Void>) criteriaDelete, null, this );
}
catch (RuntimeException e) {
if ( getSessionFactory().getJpaMetamodel().getJpaCompliance().isJpaTransactionComplianceEnabled() ) {
@ -1338,7 +1293,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
@SuppressWarnings("unused")
private void writeObject(ObjectOutputStream oos) throws IOException {
if ( log.isTraceEnabled() ) {
log.trace( "Serializing " + getClass().getSimpleName() + " [" );
@ -1389,8 +1343,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
factory = SessionFactoryImpl.deserialize( ois );
fastSessionServices = factory.getFastSessionServices();
sessionEventsManager = new SessionEventListenerManagerImpl( fastSessionServices.defaultSessionEventListeners.buildBaseline() );
jdbcSessionContext = new JdbcSessionContextImpl( this, (StatementInspector) ois.readObject(),
connectionHandlingMode, fastSessionServices );
jdbcSessionContext = createJdbcSessionContext( (StatementInspector) ois.readObject() );
jdbcCoordinator = JdbcCoordinatorImpl.deserialize( ois, this );
cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this );

View File

@ -17,7 +17,6 @@ import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -29,7 +28,6 @@ import org.hibernate.FetchNotFoundException;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.IdentifierLoadAccess;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.LobHelper;
@ -53,7 +51,6 @@ import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.binder.internal.TenantIdBinder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.internal.StatefulPersistenceContext;
@ -113,7 +110,6 @@ import org.hibernate.graph.internal.RootGraphImpl;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jpa.internal.LegacySpecHelper;
import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
@ -126,7 +122,6 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.Query;
import org.hibernate.query.SelectionQuery;
@ -154,21 +149,17 @@ import jakarta.persistence.PersistenceException;
import jakarta.persistence.TransactionRequiredException;
import jakarta.persistence.metamodel.Metamodel;
import static java.lang.Boolean.parseBoolean;
import static java.util.Collections.unmodifiableMap;
import static org.hibernate.CacheMode.fromJpaModes;
import static org.hibernate.cfg.AvailableSettings.CRITERIA_COPY_TREE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.cfg.AvailableSettings.*;
import static org.hibernate.jpa.HibernateHints.HINT_READ_ONLY;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_LOCK_TIMEOUT;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_QUERY_TIMEOUT;
import static org.hibernate.jpa.internal.util.CacheModeHelper.interpretCacheMode;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* Concrete implementation of the {@link Session} API.
@ -210,6 +201,7 @@ public class SessionImpl
private transient TransactionObserver transactionObserver;
// TODO: this is unused and can be removed
private transient boolean isEnforcingFetchGraph;
public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
@ -254,7 +246,7 @@ public class SessionImpl
final FlushMode initialMode = this.properties == null
? fastSessionServices.initialSessionFlushMode
: ConfigurationHelper.getFlushMode(
getSessionProperty(AvailableSettings.FLUSH_MODE),
getSessionProperty(FLUSH_MODE),
FlushMode.AUTO
);
setHibernateFlushMode( initialMode );
@ -269,7 +261,7 @@ public class SessionImpl
CurrentTenantIdentifierResolver resolver = factory.getCurrentTenantIdentifierResolver();
if ( resolver==null || !resolver.isRoot(tenantIdentifier) ) {
// turn on the filter, unless this is the "root" tenant with access to all partitions
getLoadQueryInfluencers()
loadQueryInfluencers
.enableFilter( TenantIdBinder.FILTER_NAME )
.setParameter( TenantIdBinder.PARAMETER_NAME, tenantIdentifier );
}
@ -536,7 +528,7 @@ public class SessionImpl
throw new NullPointerException( "null object passed to getCurrentLockMode()" );
}
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
object = lazyInitializer.getImplementation( this );
if ( object == null ) {
@ -1037,7 +1029,7 @@ public class SessionImpl
fireLoadNoChecks( event, LoadEventListener.IMMEDIATE_LOAD );
Object result = event.getResult();
finishWithEventInstance( event );
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( result );
final LazyInitializer lazyInitializer = extractLazyInitializer( result );
if ( lazyInitializer != null ) {
return lazyInitializer.getImplementation();
}
@ -1051,7 +1043,7 @@ public class SessionImpl
boolean eager,
boolean nullable) {
final LoadType type = internalLoadType( eager, nullable );
final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph();
final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph();
final GraphSemantic semantic = effectiveEntityGraph.getSemantic();
final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph();
boolean clearedEffectiveGraph = false;
@ -1500,7 +1492,7 @@ public class SessionImpl
public Object getIdentifier(Object object) throws HibernateException {
checkOpen();
checkTransactionSynchStatus();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
if ( lazyInitializer.getSession() != this ) {
throw new TransientObjectException( "The proxy was not associated with this session" );
@ -1508,7 +1500,7 @@ public class SessionImpl
return lazyInitializer.getInternalIdentifier();
}
else {
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
if ( entry == null ) {
throw new TransientObjectException( "The instance was not associated with this session" );
}
@ -1523,12 +1515,12 @@ public class SessionImpl
@Override
public Object getContextEntityIdentifier(Object object) {
checkOpenOrWaitingForAutoClose();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
return lazyInitializer.getInternalIdentifier();
}
else {
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
return entry != null ? entry.getId() : null;
}
}
@ -1543,7 +1535,7 @@ public class SessionImpl
}
try {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
//do not use proxiesByKey, since not all
//proxies that point to this session's
@ -1570,7 +1562,7 @@ public class SessionImpl
delayedAfterCompletion();
if ( entry == null ) {
if ( ! ( lazyInitializer != null ) && persistenceContext.getEntry( object ) == null ) {
if ( lazyInitializer == null && persistenceContext.getEntry( object ) == null ) {
// check if it is even an entity -> if not throw an exception (per JPA)
try {
final String entityName = getEntityNameResolver().resolveEntityName( object );
@ -1588,7 +1580,7 @@ public class SessionImpl
return false;
}
else {
return entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE;
return !entry.getStatus().isDeletedOrGone();
}
}
catch ( MappingException e ) {
@ -1609,7 +1601,7 @@ public class SessionImpl
}
try {
final LazyInitializer li = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer li = extractLazyInitializer( object );
if ( ! ( li != null ) && persistenceContext.getEntry( object ) == null ) {
// check if it is an entity -> if not throw an exception (per JPA)
try {
@ -1643,9 +1635,9 @@ public class SessionImpl
// A session is considered to contain an entity only if the entity has
// an entry in the session's persistence context and the entry reports
// that the entity has not been removed
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
delayedAfterCompletion();
return entry != null && entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE;
return entry != null && !entry.getStatus().isDeletedOrGone();
}
catch ( MappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
@ -1694,7 +1686,7 @@ public class SessionImpl
@Override
public String bestGuessEntityName(Object object) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
// it is possible for this method to be called during flush processing,
// so make certain that we do not accidentally initialize an uninitialized proxy
@ -1703,7 +1695,7 @@ public class SessionImpl
}
object = lazyInitializer.getImplementation();
}
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
if ( entry == null ) {
return guessEntityName( object );
}
@ -1716,7 +1708,7 @@ public class SessionImpl
public String getEntityName(Object object) {
checkOpen();
// checkTransactionSynchStatus();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
if ( !persistenceContext.containsProxy( object ) ) {
throw new TransientObjectException( "proxy was not associated with the session" );
@ -1734,7 +1726,7 @@ public class SessionImpl
@Override @SuppressWarnings("unchecked")
public <T> T getReference(T object) {
checkOpen();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
return (T) getReference( lazyInitializer.getPersistentClass(), lazyInitializer.getIdentifier() );
}
@ -1765,22 +1757,22 @@ public class SessionImpl
@Override
public String toString() {
StringBuilder buf = new StringBuilder( 500 )
final StringBuilder string = new StringBuilder( 500 )
.append( "SessionImpl(" ).append( System.identityHashCode( this ) );
if ( !isClosed() ) {
if ( log.isTraceEnabled() ) {
buf.append( persistenceContext )
string.append( persistenceContext )
.append( ";" )
.append( actionQueue );
}
else {
buf.append( "<open>" );
string.append( "<open>" );
}
}
else {
buf.append( "<closed>" );
string.append( "<closed>" );
}
return buf.append( ')' ).toString();
return string.append( ')' ).toString();
}
@Override
@ -2205,7 +2197,7 @@ public class SessionImpl
@Override
protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) {
this.transactionObserver = new TransactionObserver() {
transactionObserver = new TransactionObserver() {
@Override
public void afterBegin() {
}
@ -2267,27 +2259,31 @@ public class SessionImpl
@Override
public void flushBeforeTransactionCompletion() {
final boolean doFlush = isTransactionFlushable()
&& getHibernateFlushMode() != FlushMode.MANUAL;
if ( mustFlushBeforeCompletion() ) {
try {
if ( doFlush ) {
managedFlush();
}
}
catch ( RuntimeException re ) {
throw ExceptionMapperStandardImpl.INSTANCE.mapManagedFlushFailure( "error during managed flush", re, this );
throw ExceptionMapperStandardImpl.INSTANCE
.mapManagedFlushFailure( "error during managed flush", re, this );
}
}
}
private boolean mustFlushBeforeCompletion() {
return isTransactionFlushable() && getHibernateFlushMode() != FlushMode.MANUAL;
}
private boolean isTransactionFlushable() {
if ( getCurrentTransaction() == null ) {
// assume it is flushable - CMT, auto-commit, etc
return true;
}
else {
final TransactionStatus status = getCurrentTransaction().getStatus();
return status == TransactionStatus.ACTIVE || status == TransactionStatus.COMMITTING;
}
}
@Override
public SessionImplementor getSession() {
@ -2354,35 +2350,31 @@ public class SessionImpl
checkOpen();
LockOptions lockOptions = null;
try {
getLoadQueryInfluencers().getEffectiveEntityGraph().applyConfiguredGraph( properties );
Boolean readOnly = properties == null ? null : (Boolean) properties.get( HINT_READ_ONLY );
getLoadQueryInfluencers().setReadOnly( readOnly );
final IdentifierLoadAccess<T> loadAccess = byId( entityClass );
loadAccess.with( determineAppropriateLocalCacheMode( properties ) );
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeededForUpdateOperation();
}
checkTransactionNeededForLock( lockModeType );
lockOptions = buildLockOptions( lockModeType, properties );
loadAccess.with( lockOptions );
}
if ( getLoadQueryInfluencers().getEffectiveEntityGraph().getSemantic() == GraphSemantic.FETCH ) {
final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph();
effectiveEntityGraph.applyConfiguredGraph( properties );
loadQueryInfluencers.setReadOnly( getReadOnlyHint( properties ) );
if ( effectiveEntityGraph.getSemantic() == GraphSemantic.FETCH ) {
setEnforcingFetchGraph( true );
}
return loadAccess.load( primaryKey );
return byId( entityClass )
.with( determineAppropriateLocalCacheMode( properties ) )
.with( lockOptions )
.load( primaryKey );
}
catch (EntityNotFoundException entityNotFoundException) {
catch ( EntityNotFoundException enfe ) {
/*
This may happen if the entity has an associations mapped with @NotFound(action = NotFoundAction.EXCEPTION)
and this associated entity is not found.
*/
if ( entityNotFoundException instanceof FetchNotFoundException ) {
throw entityNotFoundException;
if ( enfe instanceof FetchNotFoundException ) {
throw enfe;
}
// DefaultLoadEventListener#returnNarrowedProxy() may throw ENFE (see HHH-7861 for details),
// which find() should not throw. Find() should return null if the entity was not found.
@ -2423,12 +2415,22 @@ public class SessionImpl
throw getExceptionConverter().convert( e, lockOptions );
}
finally {
getLoadQueryInfluencers().getEffectiveEntityGraph().clear();
getLoadQueryInfluencers().setReadOnly( null );
loadQueryInfluencers.getEffectiveEntityGraph().clear();
loadQueryInfluencers.setReadOnly( null );
setEnforcingFetchGraph( false );
}
}
private void checkTransactionNeededForLock(LockModeType lockModeType) {
if ( lockModeType != LockModeType.NONE ) {
checkTransactionNeededForUpdateOperation();
}
}
private static Boolean getReadOnlyHint(Map<String, Object> properties) {
return properties == null ? null : (Boolean) properties.get( HINT_READ_ONLY );
}
protected CacheMode determineAppropriateLocalCacheMode(Map<String, Object> localProperties) {
CacheRetrieveMode retrieveMode = null;
CacheStoreMode storeMode = null;
@ -2444,23 +2446,21 @@ public class SessionImpl
// use the EM setting
storeMode = fastSessionServices.getCacheStoreMode( this.properties );
}
return CacheModeHelper.interpretCacheMode( storeMode, retrieveMode );
return interpretCacheMode( storeMode, retrieveMode );
}
private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE );
if ( cacheRetrieveMode == null ) {
return (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE );
}
return cacheRetrieveMode;
return cacheRetrieveMode == null
? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE )
: cacheRetrieveMode;
}
private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE );
if ( cacheStoreMode == null ) {
return ( CacheStoreMode ) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE );
}
return cacheStoreMode;
return cacheStoreMode == null
? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE )
: cacheStoreMode;
}
private void checkTransactionNeededForUpdateOperation() {
@ -2546,10 +2546,7 @@ public class SessionImpl
}
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeededForUpdateOperation();
}
checkTransactionNeededForLock( lockModeType );
lockOptions = buildLockOptions( lockModeType, properties );
refresh( entity, lockOptions );
}
@ -2612,26 +2609,28 @@ public class SessionImpl
checkOpen();
if ( !( value instanceof Serializable ) ) {
log.warnf( "Property '%s' is not serializable, value won't be set.", propertyName );
log.warnf( "Property '%s' is not serializable, value won't be set", propertyName );
return;
}
if ( propertyName == null ) {
log.warn( "Property having key null is illegal; value won't be set." );
log.warn( "Property having key null is illegal, value won't be set" );
return;
}
//Store property for future reference:
// store property for future reference:
if ( properties == null ) {
properties = computeCurrentSessionProperties();
}
properties.put( propertyName, value );
//now actually update settings, if it's any of these which have a direct impact on this Session state:
// now actually update the setting, if it's one which affects this Session
interpretProperty( propertyName, value );
}
private void interpretProperty(String propertyName, Object value) {
switch ( propertyName ) {
case AvailableSettings.FLUSH_MODE:
case FLUSH_MODE:
setHibernateFlushMode( ConfigurationHelper.getFlushMode(value, FlushMode.AUTO) );
break;
case JPA_LOCK_SCOPE:
@ -2651,7 +2650,7 @@ public class SessionImpl
properties.put( JPA_SHARED_CACHE_RETRIEVE_MODE, value );
properties.put( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, value );
setCacheMode(
CacheModeHelper.interpretCacheMode(
interpretCacheMode(
determineCacheStoreMode( properties ),
(CacheRetrieveMode) value
)
@ -2662,23 +2661,23 @@ public class SessionImpl
properties.put( JPA_SHARED_CACHE_STORE_MODE, value );
properties.put( JAKARTA_SHARED_CACHE_STORE_MODE, value );
setCacheMode(
CacheModeHelper.interpretCacheMode(
interpretCacheMode(
(CacheStoreMode) value,
determineCacheRetrieveMode( properties )
)
);
break;
case CRITERIA_COPY_TREE:
setCriteriaCopyTreeEnabled( Boolean.parseBoolean( value.toString() ) );
setCriteriaCopyTreeEnabled( parseBoolean( value.toString() ) );
break;
}
}
private Map<String, Object> computeCurrentSessionProperties() {
final HashMap<String, Object> map = new HashMap<>( fastSessionServices.defaultSessionProperties );
final Map<String, Object> map = new HashMap<>( fastSessionServices.defaultSessionProperties );
//The FLUSH_MODE is always set at Session creation time,
//so it needs special treatment to not eagerly initialize this Map:
map.put( AvailableSettings.FLUSH_MODE, getHibernateFlushMode().name() );
map.put( FLUSH_MODE, getHibernateFlushMode().name() );
return map;
}
@ -2687,7 +2686,7 @@ public class SessionImpl
if ( properties == null ) {
properties = computeCurrentSessionProperties();
}
return Collections.unmodifiableMap( properties );
return unmodifiableMap( properties );
}
@Override
@ -2734,8 +2733,8 @@ public class SessionImpl
try {
return createStoredProcedureCall( procedureName, resultSetMappings );
}
catch (UnknownSqlResultSetMappingException unknownResultSetMapping) {
throw new IllegalArgumentException( unknownResultSetMapping.getMessage(), unknownResultSetMapping );
catch ( UnknownSqlResultSetMappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
}
catch ( RuntimeException e ) {
@ -2902,12 +2901,12 @@ public class SessionImpl
return readOnly;
}
@Override
@Override @Deprecated(forRemoval = true)
public boolean isEnforcingFetchGraph() {
return this.isEnforcingFetchGraph;
return isEnforcingFetchGraph;
}
@Override
@Override @Deprecated(forRemoval = true)
public void setEnforcingFetchGraph(boolean isEnforcingFetchGraph) {
this.isEnforcingFetchGraph = isEnforcingFetchGraph;
}

View File

@ -26,11 +26,8 @@ import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.spi.EventSource;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.generator.Generator;
import org.hibernate.generator.BeforeExecutionGenerator;
@ -44,6 +41,8 @@ import static org.hibernate.engine.internal.Versioning.incrementVersion;
import static org.hibernate.engine.internal.Versioning.seedVersion;
import static org.hibernate.engine.internal.Versioning.setVersion;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.pretty.MessageHelper.infoString;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* Concrete implementation of the {@link StatelessSession} API.
@ -129,9 +128,9 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public void delete(String entityName, Object entity) {
checkOpen();
EntityPersister persister = getEntityPersister( entityName, entity );
Object id = persister.getIdentifier( entity, this );
Object version = persister.getVersion( entity );
final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
final Object version = persister.getVersion( entity );
persister.delete( id, version, entity, this );
}
@ -147,13 +146,13 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public void update(String entityName, Object entity) {
checkOpen();
EntityPersister persister = getEntityPersister( entityName, entity );
Object id = persister.getIdentifier( entity, this );
Object[] state = persister.getValues( entity );
Object oldVersion;
final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
final Object[] state = persister.getValues( entity );
final Object oldVersion;
if ( persister.isVersioned() ) {
oldVersion = persister.getVersion( entity );
Object newVersion = incrementVersion( entity, oldVersion, persister, this );
final Object newVersion = incrementVersion( entity, oldVersion, persister, this );
setVersion( state, newVersion, persister );
persister.setValues( entity, state );
}
@ -185,9 +184,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public Object get(String entityName, Object id, LockMode lockMode) {
checkOpen();
final EntityPersister entityDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
final EntityPersister entityDescriptor = getEntityPersister( entityName );
final Object result = entityDescriptor.load( id, null, getNullSafeLockMode( lockMode ), this );
if ( temporaryPersistenceContext.isLoadFinished() ) {
@ -196,6 +193,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return result;
}
private EntityPersister getEntityPersister(String entityName) {
return getFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor( entityName );
}
@Override
public void refresh(Object entity) {
refresh( bestGuessEntityName( entity ), entity, LockMode.NONE );
@ -213,20 +214,11 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public void refresh(String entityName, Object entity, LockMode lockMode) {
final EntityPersister persister = this.getEntityPersister( entityName, entity );
final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Refreshing transient {0}", MessageHelper.infoString( persister, id, this.getFactory() ) );
LOG.tracev( "Refreshing transient {0}", infoString( persister, id, getFactory() ) );
}
// TODO : can this ever happen???
// EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
// if ( source.getPersistenceContext().getEntry( key ) != null ) {
// throw new PersistentObjectException(
// "attempted to refresh transient instance when persistent " +
// "instance was already associated with the Session: " +
// MessageHelper.infoString( persister, id, source.getFactory() )
// );
// }
if ( persister.canWriteToCache() ) {
final EntityDataAccess cacheAccess = persister.getCacheAccessStrategy();
@ -241,7 +233,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
String previousFetchProfile = getLoadQueryInfluencers().getInternalFetchProfile();
final String previousFetchProfile = getLoadQueryInfluencers().getInternalFetchProfile();
Object result;
try {
getLoadQueryInfluencers().setInternalFetchProfile( "refresh" );
@ -276,10 +268,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public Object instantiate(
String entityName,
Object id) throws HibernateException {
final EntityPersister entityDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
return instantiate( entityDescriptor, id );
return instantiate( getEntityPersister( entityName ), id );
}
@Override
@ -296,10 +285,8 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
boolean nullable) throws HibernateException {
checkOpen();
final EntityPersister entityDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
final EntityKey entityKey = generateEntityKey( id, entityDescriptor );
final EntityPersister persister = getEntityPersister( entityName );
final EntityKey entityKey = generateEntityKey( id, persister );
// first, try to load it from the temp PC associated to this SS
final PersistenceContext persistenceContext = getPersistenceContext();
@ -316,24 +303,24 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
// first, check to see if we can use "bytecode proxies"
final EntityMetamodel entityMetamodel = entityDescriptor.getEntityMetamodel();
final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata();
if ( bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) {
// if the entity defines a HibernateProxy factory, see if there is an
// existing proxy associated with the PC - and if so, use it
if ( entityDescriptor.getRepresentationStrategy().getProxyFactory() != null ) {
if ( persister.getRepresentationStrategy().getProxyFactory() != null ) {
final Object proxy = persistenceContext.getProxy( entityKey );
if ( proxy != null ) {
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Entity proxy found in session cache" );
}
if ( LOG.isDebugEnabled() && HibernateProxy.extractLazyInitializer( proxy ).isUnwrap() ) {
if ( LOG.isDebugEnabled() && extractLazyInitializer( proxy ).isUnwrap() ) {
LOG.debug( "Ignoring NO_PROXY to honor laziness" );
}
return persistenceContext.narrowProxy( proxy, entityDescriptor, entityKey, null );
return persistenceContext.narrowProxy( proxy, persister, entityKey, null );
}
// specialized handling for entities with subclasses with a HibernateProxy factory
@ -352,10 +339,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
// The entity will get loaded below.
}
else {
if ( entityDescriptor.hasProxy() ) {
if ( persister.hasProxy() ) {
final Object existingProxy = persistenceContext.getProxy( entityKey );
if ( existingProxy != null ) {
return persistenceContext.narrowProxy( existingProxy, entityDescriptor, entityKey, null );
return persistenceContext.narrowProxy( existingProxy, persister, entityKey, null );
}
else {
return createProxy( entityKey );
@ -387,7 +374,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public void fetch(Object association) {
checkOpen();
PersistenceContext persistenceContext = getPersistenceContext();
final LazyInitializer initializer = HibernateProxy.extractLazyInitializer( association );
final LazyInitializer initializer = extractLazyInitializer( association );
if ( initializer != null ) {
if ( initializer.isUninitialized() ) {
String entityName = initializer.getEntityName();
@ -411,9 +398,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
else if ( isPersistentAttributeInterceptable( association ) ) {
final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( association ).$$_hibernate_getInterceptor();
final PersistentAttributeInterceptor interceptor =
asPersistentAttributeInterceptable( association ).$$_hibernate_getInterceptor();
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor) {
EnhancementAsProxyLazinessInterceptor proxyInterceptor =
final EnhancementAsProxyLazinessInterceptor proxyInterceptor =
(EnhancementAsProxyLazinessInterceptor) interceptor;
proxyInterceptor.setSession( this );
try {
@ -428,13 +416,13 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
else if ( association instanceof PersistentCollection ) {
PersistentCollection<?> persistentCollection = (PersistentCollection<?>) association;
final PersistentCollection<?> persistentCollection = (PersistentCollection<?>) association;
if ( !persistentCollection.wasInitialized() ) {
final CollectionPersister collectionDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getCollectionDescriptor( persistentCollection.getRole() );
Object key = persistentCollection.getKey();
final Object key = persistentCollection.getKey();
persistenceContext.addUninitializedCollection( collectionDescriptor, persistentCollection, key );
persistentCollection.setCurrentSession(this);
try {
@ -460,7 +448,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return isAutoCloseSessionEnabled() && !isClosed();
}
private boolean isFlushModeNever() {
return false;
}
@ -479,31 +466,13 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public String bestGuessEntityName(Object object) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
object = lazyInitializer.getImplementation();
}
return guessEntityName( object );
}
// @Override
// public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// queryParameters.validateParameters();
// HQLQueryPlan plan = getQueryPlan( query, false );
// boolean success = false;
// int result = 0;
// try {
// result = plan.performExecuteUpdate( queryParameters, this );
// success = true;
// }
// finally {
// afterOperation( success );
// }
// temporaryPersistenceContext.clear();
// return result;
// }
@Override
public CacheMode getCacheMode() {
return CacheMode.IGNORE;
@ -535,17 +504,9 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public EntityPersister getEntityPersister(String entityName, Object object)
throws HibernateException {
checkOpen();
if ( entityName == null ) {
return getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( guessEntityName( object ) );
}
else {
return getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName )
.getSubclassEntityPersister( object, getFactory() );
}
return entityName == null
? getEntityPersister( guessEntityName(object) )
: getEntityPersister( entityName ).getSubclassEntityPersister( object, getFactory() );
}
@Override
@ -582,16 +543,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return null;
}
@Override
public boolean isEventSource() {
return false;
}
@Override
public EventSource asEventSource() {
throw new HibernateException( "Illegal Cast to EventSource - guard by invoking isEventSource() first" );
}
public boolean isDefaultReadOnly() {
return false;
}
@ -606,23 +557,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
//TODO: COPY/PASTE FROM SessionImpl, pull up!
// @Override
// public List list(String query, QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// queryParameters.validateParameters();
// HQLQueryPlan plan = getQueryPlan( query, false );
// boolean success = false;
// List results = Collections.EMPTY_LIST;
// try {
// results = plan.performList( queryParameters, this );
// success = true;
// }
// finally {
// afterOperation( success );
// }
// temporaryPersistenceContext.clear();
// return results;
// }
public void afterOperation(boolean success) {
temporaryPersistenceContext.clear();
@ -656,30 +590,8 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return false;
}
// @Override
// public int executeNativeUpdate(
// NativeSQLQuerySpecification nativeSQLQuerySpecification,
// QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// queryParameters.validateParameters();
// NativeSQLQueryPlan plan = getNativeQueryPlan( nativeSQLQuerySpecification );
//
// boolean success = false;
// int result = 0;
// try {
// result = plan.performExecuteUpdate( queryParameters, this );
// success = true;
// }
// finally {
// afterOperation( success );
// }
// temporaryPersistenceContext.clear();
// return result;
// }
@Override
public void afterTransactionBegin() {
}
@Override
@ -703,12 +615,9 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public void flushBeforeTransactionCompletion() {
boolean flush;
try {
flush = (
!isClosed()
flush = !isClosed()
&& !isFlushModeNever()
&& !JtaStatusHelper.isRollback(
getJtaPlatform().getCurrentStatus()
) );
&& !JtaStatusHelper.isRollback( getJtaPlatform().getCurrentStatus() );
}
catch ( SystemException se ) {
throw new HibernateException( "could not determine transaction status in beforeCompletion()", se );

View File

@ -77,8 +77,7 @@ public class CacheEntityLoaderHelper {
// 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 ) {
if ( oldEntry.getStatus().isDeletedOrGone() ) {
LoadingLogger.LOGGER.debug(
"Load request found matching entity in context, but it is scheduled for removal; returning null" );
return new PersistenceContextEntry( old, EntityStatus.REMOVED_ENTITY_MARKER );
@ -136,8 +135,7 @@ public class CacheEntityLoaderHelper {
// 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 ) {
if ( oldEntry.getStatus().isDeletedOrGone() ) {
LoadingLogger.LOGGER.debug(
"Load request found matching entity in context, but it is scheduled for removal; returning null" );
return new PersistenceContextEntry( old, EntityStatus.REMOVED_ENTITY_MARKER );

View File

@ -209,7 +209,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) {
// make sure it is not DELETED
final EntityEntry entry = persistenceContext.getEntry( entity );
if ( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE ) {
if ( entry.getStatus().isDeletedOrGone() ) {
// the entity is locally deleted, and the options ask that we not return such entities...
entity = null;
}

View File

@ -134,7 +134,7 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, Jav
String entityName = entityPersister.getEntityName();
Boolean readOnly = this.readOnly != null ? this.readOnly : loadQueryInfluencers.getReadOnly();
if ( this.lockOptions != null ) {
if ( lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityName, lockOptions, eventSource, readOnly );
context.fireLoad( event, LoadEventListener.LOAD );
return (T) event.getResult();
@ -179,7 +179,7 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, Jav
String entityName = entityPersister.getEntityName();
Boolean readOnly = this.readOnly != null ? this.readOnly : loadQueryInfluencers.getReadOnly();
if ( this.lockOptions != null ) {
if ( lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityName, lockOptions, eventSource, readOnly );
context.fireLoad( event, LoadEventListener.GET );
final Object result = event.getResult();

View File

@ -692,8 +692,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
// todo (6.0): do we really need this check ?
if ( entry != null ) {
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
if ( entry.getStatus().isDeletedOrGone() ) {
return;
}
}

View File

@ -431,7 +431,7 @@ public class MultiLoadTest {
final EntityEntry entry = session.getPersistenceContext()
.getEntry( deletedEntity );
assertTrue( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE );
assertTrue( entry.getStatus().isDeletedOrGone() );
final int paramCount = StringHelper.countUnquoted(
statementInspector.getSqlQueries().get( 0 ),
@ -496,9 +496,8 @@ public class MultiLoadTest {
.equals( 2 ) ).findAny().orElse( null );
assertNotNull( deletedEntity );
final EntityEntry entry = ( (SharedSessionContractImplementor) session ).getPersistenceContext()
.getEntry( deletedEntity );
assertTrue( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE );
final EntityEntry entry = session.getPersistenceContext().getEntry( deletedEntity );
assertTrue( entry.getStatus().isDeletedOrGone() );
final int paramCount = StringHelper.countUnquoted(
statementInspector.getSqlQueries().get( 0 ),