many misc cleanups and doc for the Session hierarchy
This commit is contained in:
parent
974fe9e22d
commit
fc62f33a55
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -18,5 +18,9 @@ public enum Status {
|
|||
DELETED,
|
||||
GONE,
|
||||
LOADING,
|
||||
SAVING
|
||||
SAVING;
|
||||
|
||||
public boolean isDeletedOrGone() {
|
||||
return this == DELETED || this == GONE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ),
|
||||
|
|
Loading…
Reference in New Issue