diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index 5daa9e7254e1..abc2c2f3eec6 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -1415,14 +1415,6 @@ public interface Session extends SharedSessionContract, EntityManager { @Incubating Collection getManagedEntities(EntityType entityType); - /** - * Obtain a {@link Session} builder with the ability to copy certain - * information from this session. - * - * @return the session builder - */ - SharedSessionBuilder sessionWithOptions(); - /** * Add one or more listeners to the Session * diff --git a/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java index 703b5b9be449..3cbfaf593111 100644 --- a/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java @@ -33,6 +33,12 @@ public interface SessionBuilder extends CommonBuilder { @Override SessionBuilder noInterceptor(); + @Override + SessionBuilder noSessionInterceptorCreation(); + + @Override + SessionBuilder noStatementInspector(); + @Override SessionBuilder statementInspector(UnaryOperator operator); @@ -169,6 +175,7 @@ public interface SessionBuilder extends CommonBuilder { * * @return {@code this}, for method chaining */ + @Override SessionBuilder jdbcTimeZone(TimeZone timeZone); /** diff --git a/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java index 7983ae2f6fff..aa73b84f171a 100644 --- a/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java @@ -71,6 +71,12 @@ public interface SharedSessionBuilder extends SessionBuilder, CommonSharedBuilde @Override SharedSessionBuilder statementInspector(UnaryOperator operator); + @Override + SharedSessionBuilder statementInspector(); + + @Override + SharedSessionBuilder noStatementInspector(); + @Override @Deprecated SharedSessionBuilder connectionHandlingMode(PhysicalConnectionHandlingMode mode); @@ -110,6 +116,9 @@ public interface SharedSessionBuilder extends SessionBuilder, CommonSharedBuilde @Override SharedSessionBuilder noInterceptor(); + @Override + SharedSessionBuilder noSessionInterceptorCreation(); + @Override SharedSessionBuilder connection(Connection connection); diff --git a/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java index 36c692e338ac..40be308448b8 100644 --- a/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java @@ -38,6 +38,14 @@ public interface SharedSessionContract extends QueryProducer, AutoCloseable, Ser @Incubating SharedStatelessSessionBuilder statelessWithOptions(); + /** + * Obtain a {@link Session} builder with the ability to copy certain + * information from this session. + * + * @return the session builder + */ + SharedSessionBuilder sessionWithOptions(); + /** * Obtain the tenant identifier associated with this session, as a string. * diff --git a/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java index 8243586d1341..0a6323f9312f 100644 --- a/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java @@ -6,6 +6,8 @@ import org.hibernate.engine.creation.CommonSharedBuilder; +import java.sql.Connection; +import java.util.TimeZone; import java.util.function.UnaryOperator; /** @@ -21,7 +23,7 @@ * @author Steve Ebersole */ @Incubating -public interface SharedStatelessSessionBuilder extends CommonSharedBuilder { +public interface SharedStatelessSessionBuilder extends StatelessSessionBuilder, CommonSharedBuilder { /** * Open the stateless session. */ @@ -39,6 +41,9 @@ public interface SharedStatelessSessionBuilder extends CommonSharedBuilder { @Override SharedStatelessSessionBuilder noInterceptor(); + @Override + SharedStatelessSessionBuilder noSessionInterceptorCreation(); + SharedStatelessSessionBuilder statementInspector(UnaryOperator operator); @Override @@ -55,4 +60,13 @@ public interface SharedStatelessSessionBuilder extends CommonSharedBuilder { @Override SharedStatelessSessionBuilder initialCacheMode(CacheMode cacheMode); + + @Override + SharedStatelessSessionBuilder connection(Connection connection); + + @Override + SharedStatelessSessionBuilder connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode); + + @Override + SharedStatelessSessionBuilder jdbcTimeZone(TimeZone timeZone); } diff --git a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java index 31cd8c719a99..17a968aea794 100644 --- a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java +++ b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java @@ -79,10 +79,6 @@ * @author Gavin King */ public interface StatelessSession extends SharedSessionContract { - /** - * Close the stateless session and release the JDBC connection. - */ - void close(); /** * Insert a record. diff --git a/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java index 6f8658497490..29e1a1ebe008 100644 --- a/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java @@ -5,6 +5,7 @@ package org.hibernate; import java.sql.Connection; +import java.util.TimeZone; import java.util.function.UnaryOperator; import org.hibernate.engine.creation.CommonBuilder; @@ -43,6 +44,9 @@ public interface StatelessSessionBuilder extends CommonBuilder { @Override StatelessSessionBuilder statementInspector(UnaryOperator operator); + @Override + StatelessSessionBuilder jdbcTimeZone(TimeZone timeZone); + /** * Define the tenant identifier to be associated with the opened session. * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java index ff6b308a3cc6..4be9edcefbeb 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java @@ -15,6 +15,7 @@ import org.hibernate.StatelessSession; import java.sql.Connection; +import java.util.TimeZone; import java.util.function.UnaryOperator; /** @@ -59,18 +60,45 @@ public interface CommonBuilder { CommonBuilder interceptor(Interceptor interceptor); /** - * Signifies that no {@link Interceptor} should be used. + * Specifies that no {@link Interceptor} should be used. *

- * By default, if no {@code Interceptor} is explicitly specified, the + * By default, if no {@code Interceptor} is explicitly + * {@linkplain #interceptor(Interceptor) specified}, the * {@code Interceptor} associated with the {@link SessionFactory} is - * inherited by the new session. + * inherited by the new session. Or, if there is no interceptor + * associated with the {@link SessionFactory}, but a session-scoped + * interceptor has been configured, a new session-scoped + * {@code Interceptor} will be created for the new session. *

- * Calling {@link #interceptor(Interceptor)} with null has the same effect. + * Calling {@link #interceptor(Interceptor) interceptor(null)} has the + * same effect. * * @return {@code this}, for method chaining */ CommonBuilder noInterceptor(); + /** + * Specifies that no + * {@linkplain org.hibernate.cfg.SessionEventSettings#SESSION_SCOPED_INTERCEPTOR + * session-scoped interceptor} should be instantiated for the new session. + *

+ * By default, if no {@link Interceptor} is explicitly + * {@linkplain #interceptor(Interceptor) specified}, and if there + * is no interceptor associated with the {@link SessionFactory}, but + * a session-scoped interceptor has been configured, a new session-scoped + * {@code Interceptor} will be created for the new session. + *

+ * Note that this operation does not disable use of an interceptor + * associated with the {@link SessionFactory}. + * + * @return {@code this}, for method chaining + * + * @see org.hibernate.cfg.SessionEventSettings#SESSION_SCOPED_INTERCEPTOR + * + * @since 7.2 + */ + CommonBuilder noSessionInterceptorCreation(); + /** * Applies the given statement inspection function to the session. * @@ -157,4 +185,12 @@ public interface CommonBuilder { * @see SharedSessionContract#getCacheMode() */ CommonBuilder initialCacheMode(CacheMode cacheMode); + + /** + * Specify the {@linkplain org.hibernate.cfg.JdbcSettings#JDBC_TIME_ZONE + * JDBC time zone} for the session. + * + * @return {@code this}, for method chaining + */ + CommonBuilder jdbcTimeZone(TimeZone timeZone); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java index 81777e43b8d4..d375185e46a8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java @@ -5,11 +5,15 @@ package org.hibernate.engine.creation; import org.hibernate.CacheMode; +import org.hibernate.ConnectionAcquisitionMode; +import org.hibernate.ConnectionReleaseMode; import org.hibernate.Incubating; import org.hibernate.Interceptor; import org.hibernate.Session; import org.hibernate.StatelessSession; +import java.sql.Connection; +import java.util.TimeZone; import java.util.function.UnaryOperator; /** @@ -48,6 +52,7 @@ public interface CommonSharedBuilder extends CommonBuilder { * Signifies that no SQL {@linkplain org.hibernate.resource.jdbc.spi.StatementInspector statement inspector} * should be used. */ + @Override CommonSharedBuilder noStatementInspector(); @Override @@ -56,6 +61,9 @@ public interface CommonSharedBuilder extends CommonBuilder { @Override CommonSharedBuilder noInterceptor(); + @Override + CommonSharedBuilder noSessionInterceptorCreation(); + @Override CommonSharedBuilder statementInspector(UnaryOperator operator); @@ -67,4 +75,13 @@ public interface CommonSharedBuilder extends CommonBuilder { @Override CommonSharedBuilder tenantIdentifier(Object tenantIdentifier); + + @Override + CommonBuilder connection(Connection connection); + + @Override + CommonSharedBuilder connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode); + + @Override + CommonSharedBuilder jdbcTimeZone(TimeZone timeZone); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java index 66e4ed54068a..134e25de0c3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java @@ -9,11 +9,13 @@ import org.hibernate.ConnectionReleaseMode; import org.hibernate.Interceptor; import org.hibernate.engine.creation.CommonBuilder; -import org.hibernate.internal.SessionFactoryImpl; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.EmptyInterceptor; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import java.sql.Connection; +import java.util.TimeZone; import java.util.function.UnaryOperator; /** @@ -22,25 +24,62 @@ * @author Steve Ebersole */ public abstract class AbstractCommonBuilder implements CommonBuilder { - protected final SessionFactoryImpl sessionFactory; + protected final SessionFactoryImplementor sessionFactory; protected StatementInspector statementInspector; protected Interceptor interceptor; - protected boolean explicitNoInterceptor; + protected boolean allowInterceptor = true; + protected boolean allowSessionInterceptorCreation = true; protected Connection connection; protected PhysicalConnectionHandlingMode connectionHandlingMode; protected Object tenantIdentifier; protected boolean readOnly; protected CacheMode cacheMode; + protected TimeZone jdbcTimeZone; - public AbstractCommonBuilder(SessionFactoryImpl sessionFactory) { - this.sessionFactory = sessionFactory; - - final var options = sessionFactory.getSessionFactoryOptions(); + public AbstractCommonBuilder(SessionFactoryImplementor factory) { + sessionFactory = factory; + final var options = factory.getSessionFactoryOptions(); statementInspector = options.getStatementInspector(); cacheMode = options.getInitialSessionCacheMode(); - tenantIdentifier = sessionFactory.resolveTenantIdentifier(); connectionHandlingMode = options.getPhysicalConnectionHandlingMode(); + jdbcTimeZone = options.getJdbcTimeZone(); + tenantIdentifier = factory.resolveTenantIdentifier(); + } + + Interceptor configuredInterceptor() { + // If we were explicitly asked for no interceptor, always return null. + if ( !allowInterceptor ) { + return null; + } + + // NOTE: DO NOT return EmptyInterceptor.INSTANCE from here as a "default for the Session". + // We "filter" that one out here. The interceptor returned here should represent the + // explicitly configured Interceptor (if there is one). Return null from here instead; + // Session will handle it. + + if ( interceptor != null && interceptor != EmptyInterceptor.INSTANCE ) { + return interceptor; + } + + final var options = sessionFactory.getSessionFactoryOptions(); + + // prefer the SessionFactory-scoped interceptor, prefer that to any Session-scoped interceptor prototype + final var optionsInterceptor = options.getInterceptor(); + if ( optionsInterceptor != null && optionsInterceptor != EmptyInterceptor.INSTANCE ) { + return optionsInterceptor; + } + + if ( allowSessionInterceptorCreation ) { + // then check the Session-scoped interceptor prototype + final var statelessInterceptorImplementorSupplier = + options.getStatelessInterceptorImplementorSupplier(); + if ( statelessInterceptorImplementorSupplier != null ) { + return statelessInterceptorImplementorSupplier.get(); + } + } + + return null; } protected abstract T getThis(); @@ -64,7 +103,7 @@ public T interceptor(Interceptor interceptor) { } else { this.interceptor = interceptor; - this.explicitNoInterceptor = false; + this.allowInterceptor = true; } return getThis(); } @@ -72,7 +111,13 @@ public T interceptor(Interceptor interceptor) { @Override public T noInterceptor() { this.interceptor = null; - this.explicitNoInterceptor = true; + this.allowInterceptor = false; + return getThis(); + } + + @Override + public T noSessionInterceptorCreation() { + this.allowSessionInterceptorCreation = false; return getThis(); } @@ -110,4 +155,10 @@ public T noStatementInspector() { this.statementInspector = null; return getThis(); } + + @Override + public T jdbcTimeZone(TimeZone timeZone) { + jdbcTimeZone = timeZone; + return getThis(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CommonSharedSessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/internal/CommonSharedSessionCreationOptions.java rename to hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java index db405a783090..03260144be35 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CommonSharedSessionCreationOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/CommonSharedSessionCreationOptions.java @@ -2,21 +2,29 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.internal; +package org.hibernate.engine.creation.internal; import org.hibernate.CacheMode; import org.hibernate.Interceptor; +import org.hibernate.Transaction; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.transaction.spi.TransactionCoordinator; +import java.util.TimeZone; + + /** * Creation options for shared {@linkplain org.hibernate.engine.spi.SessionImplementor stateful} * and {@linkplain org.hibernate.engine.spi.StatelessSessionImplementor stateless} sessions. * - * @implNote At the moment this is only used in the creation of {@linkplain org.hibernate.engine.spi.StatelessSessionImplementor stateless} sessions. + * @implNote At the moment this is only used in the creation of + * {@linkplain org.hibernate.engine.spi.StatelessSessionImplementor stateless sessions}. * * @author Steve Ebersole + * + * @since 7.2 */ public interface CommonSharedSessionCreationOptions { @@ -30,7 +38,12 @@ public interface CommonSharedSessionCreationOptions { CacheMode getInitialCacheMode(); + PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode(); + boolean isTransactionCoordinatorShared(); TransactionCoordinator getTransactionCoordinator(); JdbcCoordinator getJdbcCoordinator(); + Transaction getTransaction(); + + TimeZone getJdbcTimeZone(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java index cf104bcdd743..c58714990354 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java @@ -9,9 +9,9 @@ import org.hibernate.Interceptor; import org.hibernate.SessionEventListener; import org.hibernate.engine.creation.spi.SessionBuilderImplementor; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.SessionFactoryImpl; -import org.hibernate.internal.SessionImpl; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.jboss.logging.Logger; @@ -28,17 +28,18 @@ * * @author Steve Ebersole */ -public class SessionBuilderImpl +public abstract class SessionBuilderImpl extends AbstractCommonBuilder implements SessionBuilderImplementor, SessionCreationOptions { - private static final Logger log = CoreLogging.logger( SessionBuilderImpl.class ); + + private static final Logger LOG = CoreLogging.logger( SessionBuilderImpl.class ); private boolean autoJoinTransactions = true; - private FlushMode flushMode; private boolean autoClose; private boolean autoClear; private boolean identifierRollback; - private TimeZone jdbcTimeZone; + private FlushMode flushMode; + private final int defaultBatchFetchSize; private final boolean subselectFetchEnabled; @@ -47,21 +48,14 @@ public class SessionBuilderImpl // Only initialize of the builder is overriding the default. private List listeners; - public SessionBuilderImpl(SessionFactoryImpl sessionFactory) { + public SessionBuilderImpl(SessionFactoryImplementor sessionFactory) { super( sessionFactory ); - - // set up default builder values... + // set up default builder values final var options = sessionFactory.getSessionFactoryOptions(); - statementInspector = options.getStatementInspector(); - connectionHandlingMode = options.getPhysicalConnectionHandlingMode(); autoClose = options.isAutoCloseSessionEnabled(); + identifierRollback = options.isIdentifierRollbackEnabled(); defaultBatchFetchSize = options.getDefaultBatchFetchSize(); subselectFetchEnabled = options.isSubselectFetchEnabled(); - identifierRollback = options.isIdentifierRollbackEnabled(); - cacheMode = options.getInitialSessionCacheMode(); - - tenantIdentifier = sessionFactory.resolveTenantIdentifier(); - jdbcTimeZone = options.getJdbcTimeZone(); } @Override @@ -110,8 +104,7 @@ public Connection getConnection() { @Override public Interceptor getInterceptor() { - return SessionFactoryImpl.configuredInterceptor( interceptor, explicitNoInterceptor, - sessionFactory.getSessionFactoryOptions() ); + return configuredInterceptor(); } @Override @@ -124,13 +117,6 @@ public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() { return connectionHandlingMode; } - @Override - public String getTenantIdentifier() { - return tenantIdentifier != null - ? sessionFactory.getTenantIdentifierJavaType().toString( tenantIdentifier ) - : null; - } - @Override public Object getTenantIdentifierValue() { return tenantIdentifier; @@ -157,7 +143,7 @@ public TimeZone getJdbcTimeZone() { } @Override - public List getCustomSessionEventListener() { + public List getCustomSessionEventListeners() { return listeners; } @@ -165,11 +151,13 @@ public List getCustomSessionEventListener() { // SessionBuilder @Override - public SessionImpl openSession() { - log.tracef( "Opening Hibernate Session. tenant=%s", tenantIdentifier ); - return new SessionImpl( sessionFactory, this ); + public SessionImplementor openSession() { + LOG.tracef( "Opening Hibernate Session [tenant=%s]", tenantIdentifier ); + return createSession(); } + protected abstract SessionImplementor createSession(); + @Override @Deprecated public SessionBuilderImplementor statementInspector(StatementInspector statementInspector) { @@ -244,12 +232,4 @@ public SessionBuilderImplementor clearEventListeners() { } return this; } - - @Override - public SessionBuilderImplementor jdbcTimeZone(TimeZone timeZone) { - jdbcTimeZone = timeZone; - return this; - } - - } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java index 2027f4c9dabb..b09fede8a06e 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java @@ -21,6 +21,8 @@ * used when creating sessions. * * @author Steve Ebersole + * + * @since 7.2 */ public interface SessionCreationOptions { @@ -44,8 +46,6 @@ public interface SessionCreationOptions { PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode(); - String getTenantIdentifier(); - Object getTenantIdentifierValue(); boolean isReadOnly(); @@ -60,5 +60,5 @@ public interface SessionCreationOptions { * @return the full list of SessionEventListener if this was customized, * or null if this Session is being created with the default list. */ - List getCustomSessionEventListener(); + List getCustomSessionEventListeners(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java new file mode 100644 index 000000000000..47692b72bd46 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptionsAdaptor.java @@ -0,0 +1,146 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.engine.creation.internal; + +import org.hibernate.CacheMode; +import org.hibernate.FlushMode; +import org.hibernate.Interceptor; +import org.hibernate.SessionEventListener; +import org.hibernate.Transaction; +import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; +import org.hibernate.resource.jdbc.spi.StatementInspector; +import org.hibernate.resource.transaction.spi.TransactionCoordinator; + +import java.sql.Connection; +import java.util.List; +import java.util.TimeZone; + +/** + * Wraps a {@link CommonSharedSessionCreationOptions} as a + * {@link SharedSessionCreationOptions} to pass to + * {@link org.hibernate.internal.AbstractSharedSessionContract} + * during construction. + * + * @param factory The {@code SessionFactoryImplementor} + * @param options The {@code CommonSharedSessionCreationOptions} being wrapped. + */ +public record SessionCreationOptionsAdaptor( + SessionFactoryImplementor factory, + CommonSharedSessionCreationOptions options) + implements SharedSessionCreationOptions { + + @Override + public Interceptor getInterceptor() { + return options.getInterceptor(); + } + + @Override + public StatementInspector getStatementInspector() { + return options.getStatementInspector(); + } + + @Override + public Object getTenantIdentifierValue() { + return options.getTenantIdentifierValue(); + } + + @Override + public boolean isReadOnly() { + return options.isReadOnly(); + } + + @Override + public CacheMode getInitialCacheMode() { + return options.getInitialCacheMode(); + } + + @Override + public boolean shouldAutoJoinTransactions() { + return true; + } + + @Override + public FlushMode getInitialSessionFlushMode() { + // stateless sessions don't have a flush mode + return FlushMode.AUTO; + } + + @Override + public boolean isSubselectFetchEnabled() { + // for some reason, StatelessSession has no setSubselectFetchEnabled() + return false; + } + + @Override + public int getDefaultBatchFetchSize() { + // for some reason, StatelessSession has no setFetchBatchSize() + return -1; + } + + @Override + public boolean shouldAutoClose() { + return false; + } + + @Override + public boolean shouldAutoClear() { + return false; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public boolean isIdentifierRollbackEnabled() { + // identifier rollback not yet implemented for StatelessSessions + return false; + } + + @Override + public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() { + return options.getPhysicalConnectionHandlingMode(); + } + + @Override + public TimeZone getJdbcTimeZone() { + // not exposed via SharedStatelessSessionBuilder + return options.getJdbcTimeZone(); + } + + @Override + public List getCustomSessionEventListeners() { + return null; + } + + @Override + public boolean isTransactionCoordinatorShared() { + return options.isTransactionCoordinatorShared(); + } + + @Override + public TransactionCoordinator getTransactionCoordinator() { + return options.getTransactionCoordinator(); + } + + @Override + public JdbcCoordinator getJdbcCoordinator() { + return options.getJdbcCoordinator(); + } + + @Override + public Transaction getTransaction() { + return options.getTransaction(); + } + + @Override + public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java index 3d92e28d1f49..ecf9977dc6c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java @@ -6,7 +6,6 @@ import org.hibernate.CacheMode; import org.hibernate.ConnectionAcquisitionMode; -import org.hibernate.ConnectionReleaseMode; import org.hibernate.FlushMode; import org.hibernate.Interceptor; import org.hibernate.SessionEventListener; @@ -15,42 +14,79 @@ import org.hibernate.engine.creation.spi.SharedSessionBuilderImplementor; import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; -import org.hibernate.internal.SessionFactoryImpl; -import org.hibernate.internal.SessionImpl; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.CoreLogging; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.transaction.spi.TransactionCoordinator; +import org.jboss.logging.Logger; import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; import java.util.TimeZone; -import java.util.function.UnaryOperator; + +import static java.util.Collections.addAll; /** * @author Steve Ebersole */ -public class SharedSessionBuilderImpl - extends SessionBuilderImpl +public abstract class SharedSessionBuilderImpl + extends AbstractCommonBuilder implements SharedSessionBuilderImplementor, SharedSessionCreationOptions { - private final SessionImpl session; + + private static final Logger LOG = CoreLogging.logger( SharedSessionBuilderImpl.class ); + + private final SharedSessionContractImplementor original; private boolean shareTransactionContext; + private boolean autoJoinTransactions = true; + private boolean autoClose; + private boolean autoClear; + private boolean identifierRollback; + private FlushMode flushMode; + private boolean tenantIdChanged; private boolean readOnlyChanged; - public SharedSessionBuilderImpl(SessionImpl session) { - super( (SessionFactoryImpl) session.getFactory() ); - this.session = session; - super.tenantIdentifier( session.getTenantIdentifierValue() ); - super.identifierRollback( session.isIdentifierRollbackEnabled() ); + private final int defaultBatchFetchSize; + private final boolean subselectFetchEnabled; + + // Lazy: defaults can be built by invoking the builder in fastSessionServices.defaultSessionEventListeners + // (Need a fresh build for each Session as the listener instances can't be reused across sessions) + // Only initialize of the builder is overriding the default. + private List listeners; + + public SharedSessionBuilderImpl(SharedSessionContractImplementor original) { + super( original.getFactory() ); + this.original = original; + final var options = sessionFactory.getSessionFactoryOptions(); + autoClose = options.isAutoCloseSessionEnabled(); + identifierRollback = options.isIdentifierRollbackEnabled(); + defaultBatchFetchSize = options.getDefaultBatchFetchSize(); + subselectFetchEnabled = options.isSubselectFetchEnabled(); + // override defaults from factory + tenantIdentifier = original.getTenantIdentifierValue(); + identifierRollback = original.isIdentifierRollbackEnabled(); + // good idea to inherit this + jdbcTimeZone = original.getJdbcTimeZone(); } + protected abstract SessionImplementor createSession(); + + @Override + protected SharedSessionBuilderImplementor getThis() { + return this; + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionBuilder @Override - public SessionImpl openSession() { - if ( session.getFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) { + public SessionImplementor openSession() { + LOG.tracef( "Opening Session [tenant=%s]", tenantIdentifier ); + if ( original.getFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) { if ( shareTransactionContext ) { if ( tenantIdChanged ) { throw new SessionException( @@ -62,10 +98,9 @@ public SessionImpl openSession() { } } } - return super.openSession(); + return createSession(); } - @Override @Deprecated(forRemoval = true) public SharedSessionBuilderImplementor tenantIdentifier(String tenantIdentifier) { @@ -89,30 +124,30 @@ public SharedSessionBuilderImplementor readOnly(boolean readOnly) { @Override public SharedSessionBuilderImplementor connection() { - this.shareTransactionContext = true; + shareTransactionContext = true; return this; } @Override public SharedSessionBuilderImplementor interceptor() { - interceptor = session.getInterceptor(); + interceptor = original.getInterceptor(); return this; } @Override public SharedSessionBuilderImplementor statementInspector() { - statementInspector = session.getJdbcSessionContext().getStatementInspector(); + statementInspector = original.getJdbcSessionContext().getStatementInspector(); return this; } private PhysicalConnectionHandlingMode getConnectionHandlingMode() { - return session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode(); + return original.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode(); } @Override @Deprecated(since = "6.0") public SharedSessionBuilderImplementor connectionReleaseMode() { - final PhysicalConnectionHandlingMode handlingMode = + final var handlingMode = PhysicalConnectionHandlingMode.interpret( ConnectionAcquisitionMode.AS_NEEDED, getConnectionHandlingMode().getReleaseMode() ); connectionHandlingMode( handlingMode ); @@ -127,155 +162,210 @@ public SharedSessionBuilderImplementor connectionHandlingMode() { @Override public SharedSessionBuilderImplementor autoJoinTransactions() { - super.autoJoinTransactions( session.shouldAutoJoinTransaction() ); + this.autoJoinTransactions = original.shouldAutoJoinTransaction(); return this; } @Override public SharedSessionBuilderImplementor autoJoinTransactions(boolean autoJoinTransactions) { - super.autoJoinTransactions( autoJoinTransactions ); + this.autoJoinTransactions = autoJoinTransactions; return this; } @Override public SharedSessionBuilderImplementor autoClose(boolean autoClose) { - super.autoClose( autoClose ); + this.autoClose = autoClose; return this; } @Override public SharedSessionBuilderImplementor flushMode() { - flushMode( session.getHibernateFlushMode() ); + flushMode( original.getHibernateFlushMode() ); return this; } @Override public SharedSessionBuilderImplementor autoClose() { - autoClose( session.isAutoCloseSessionEnabled() ); + autoClose( original instanceof SessionImplementor statefulSession + && statefulSession.isAutoCloseSessionEnabled() ); return this; } @Override public SharedSessionBuilderImplementor identifierRollback(boolean identifierRollback) { - super.identifierRollback( identifierRollback ); - return this; - } - - @Override - public SharedSessionBuilderImplementor jdbcTimeZone(TimeZone timeZone) { - super.jdbcTimeZone( timeZone ); + this.identifierRollback = identifierRollback; return this; } @Override public SharedSessionBuilderImplementor clearEventListeners() { - super.clearEventListeners(); + if ( listeners == null ) { + //Needs to initialize explicitly to an empty list as otherwise "null" implies the default listeners will be applied + listeners = new ArrayList<>( 3 ); + } + else { + listeners.clear(); + } return this; } @Override public SharedSessionBuilderImplementor flushMode(FlushMode flushMode) { - super.flushMode( flushMode ); + this.flushMode = flushMode; return this; } @Override public SharedSessionBuilderImplementor autoClear(boolean autoClear) { - super.autoClear( autoClear ); + this.autoClear = autoClear; return this; } @Override @Deprecated public SharedSessionBuilderImplementor statementInspector(StatementInspector statementInspector) { - super.statementInspector( statementInspector ); + super.statementInspector( statementInspector::inspect ); return this; } @Override - public SharedSessionBuilderImplementor statementInspector(UnaryOperator operator) { - super.statementInspector( operator ); + @Deprecated + public SharedSessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode connectionHandlingMode) { + super.connectionHandlingMode = connectionHandlingMode; return this; } @Override - @Deprecated - public SharedSessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode connectionHandlingMode) { - super.connectionHandlingMode( connectionHandlingMode ); + public SharedSessionBuilderImplementor eventListeners(SessionEventListener... listeners) { + if ( this.listeners == null ) { + final var baselineListeners = + sessionFactory.getSessionFactoryOptions().buildSessionEventListeners(); + this.listeners = new ArrayList<>( baselineListeners.length + listeners.length ); + addAll( this.listeners, baselineListeners ); + } + addAll( this.listeners, listeners ); return this; } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // SharedSessionCreationOptions + @Override - @Deprecated - public SharedSessionBuilderImplementor connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) { - super.connectionHandling( acquisitionMode, releaseMode ); - return this; + public boolean isTransactionCoordinatorShared() { + return shareTransactionContext; } @Override - public SharedSessionBuilderImplementor eventListeners(SessionEventListener... listeners) { - super.eventListeners( listeners ); - return this; + public TransactionCoordinator getTransactionCoordinator() { + return shareTransactionContext + ? original.getTransactionCoordinator() + : null; } @Override - public SharedSessionBuilderImplementor connection(Connection connection) { - super.connection( connection ); - return this; + public JdbcCoordinator getJdbcCoordinator() { + return shareTransactionContext + ? original.getJdbcCoordinator() + : null; } @Override - public SharedSessionBuilderImplementor interceptor(Interceptor interceptor) { - super.interceptor( interceptor ); - return this; + public Transaction getTransaction() { + return shareTransactionContext + ? original.getCurrentTransaction() + : null; } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CommonSharedSessionCreationOptions + @Override - public SharedSessionBuilderImplementor noInterceptor() { - super.noInterceptor(); - return this; + public Interceptor getInterceptor() { + return configuredInterceptor(); } @Override - public SharedSessionBuilderImplementor initialCacheMode(CacheMode cacheMode) { - super.initialCacheMode( cacheMode ); - return this; + public StatementInspector getStatementInspector() { + return statementInspector; } @Override - public SharedSessionBuilderImplementor noStatementInspector() { - super.noStatementInspector(); - return this; + public Object getTenantIdentifierValue() { + return tenantIdentifier; } + @Override + public boolean isReadOnly() { + return readOnly; + } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + @Override + public CacheMode getInitialCacheMode() { + return cacheMode; + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionCreationOptions @Override - public boolean isTransactionCoordinatorShared() { - return shareTransactionContext; + public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { + return null; } @Override - public TransactionCoordinator getTransactionCoordinator() { - return shareTransactionContext ? session.getTransactionCoordinator() : null; + public boolean shouldAutoJoinTransactions() { + return autoJoinTransactions; } @Override - public JdbcCoordinator getJdbcCoordinator() { - return shareTransactionContext ? session.getJdbcCoordinator() : null; + public FlushMode getInitialSessionFlushMode() { + return flushMode; } @Override - public Transaction getTransaction() { - return shareTransactionContext ? session.getCurrentTransaction() : null; + public boolean isSubselectFetchEnabled() { + return subselectFetchEnabled; } @Override - public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() { - return shareTransactionContext - ? session.getActionQueue().getTransactionCompletionCallbacks() - : null; + public int getDefaultBatchFetchSize() { + return defaultBatchFetchSize; + } + + @Override + public boolean shouldAutoClose() { + return autoClose; + } + + @Override + public boolean shouldAutoClear() { + return autoClear; + } + + @Override + public Connection getConnection() { + return connection; + } + + @Override + public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() { + return connectionHandlingMode; + } + + @Override + public boolean isIdentifierRollbackEnabled() { + return identifierRollback; + } + + @Override + public TimeZone getJdbcTimeZone() { + return jdbcTimeZone; + } + + @Override + public List getCustomSessionEventListeners() { + return listeners; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java index 72c6ccd42e4b..c7452d0b7d3e 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java @@ -17,6 +17,8 @@ * @author Steve Ebersole * * @see org.hibernate.SharedSessionBuilder + * + * @since 7.2 */ public interface SharedSessionCreationOptions extends SessionCreationOptions { boolean isTransactionCoordinatorShared(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java index 27748b74cf5b..da6973768ca8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java @@ -8,16 +8,20 @@ import org.hibernate.Interceptor; import org.hibernate.SessionException; import org.hibernate.SharedStatelessSessionBuilder; +import org.hibernate.StatelessSession; +import org.hibernate.StatelessSessionBuilder; +import org.hibernate.Transaction; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.StatelessSessionImplementor; -import org.hibernate.internal.CommonSharedSessionCreationOptions; -import org.hibernate.internal.SessionFactoryImpl; -import org.hibernate.internal.StatelessSessionImpl; +import org.hibernate.internal.CoreLogging; +import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.transaction.spi.TransactionCoordinator; +import org.jboss.logging.Logger; import java.util.Objects; +import java.util.TimeZone; /** * Builder for shared {@linkplain StatelessSessionImplementor stateless} sessions. @@ -26,22 +30,27 @@ * * @author Steve Ebersole */ -public class SharedStatelessSessionBuilderImpl +public abstract class SharedStatelessSessionBuilderImpl extends AbstractCommonBuilder implements SharedStatelessSessionBuilder, CommonSharedSessionCreationOptions { + private static final Logger LOG = CoreLogging.logger( SharedStatelessSessionBuilderImpl.class ); + protected final SharedSessionContractImplementor original; protected boolean shareTransactionContext; public SharedStatelessSessionBuilderImpl(SharedSessionContractImplementor original) { - super( (SessionFactoryImpl) original.getSessionFactory() ); + super( original.getSessionFactory() ); this.original = original; - - this.tenantIdentifier = original.getTenantIdentifierValue(); - this.interceptor = original.getSessionFactory().getSessionFactoryOptions().getInterceptor(); - this.statementInspector = original.getSessionFactory().getSessionFactoryOptions().getStatementInspector(); + final var options = original.getSessionFactory().getSessionFactoryOptions(); + statementInspector = options.getStatementInspector(); + tenantIdentifier = original.getTenantIdentifierValue(); + // good idea to inherit this + jdbcTimeZone = original.getJdbcTimeZone(); } + protected abstract StatelessSessionImplementor createStatelessSession(); + @Override protected SharedStatelessSessionBuilder getThis() { return this; @@ -52,15 +61,22 @@ protected SharedStatelessSessionBuilder getThis() { @Override public StatelessSessionImplementor open() { + LOG.tracef( "Opening StatelessSession [tenant=%s]", tenantIdentifier ); if ( original.getSessionFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) { if ( shareTransactionContext ) { - assert original.getTenantIdentifierValue() != null; - if ( Objects.equals( original.getTenantIdentifierValue(), tenantIdentifier ) ) { + final var tenantId = original.getTenantIdentifierValue(); + assert tenantId != null; + if ( Objects.equals( tenantId, tenantIdentifier ) ) { throw new SessionException( "Cannot redefine the tenant identifier on a child session if the connection is reused" ); } } } - return new StatelessSessionImpl( original.getSessionFactory(), this ); + return createStatelessSession(); + } + + @Override + public StatelessSession openStatelessSession() { + return open(); } @Override @@ -87,7 +103,7 @@ public SharedStatelessSessionBuilder statementInspector() { @Override public Interceptor getInterceptor() { - return interceptor; + return configuredInterceptor(); } @Override @@ -110,6 +126,28 @@ public CacheMode getInitialCacheMode() { return cacheMode; } + @Override + public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() { + return connectionHandlingMode; + } + + @Override + public TimeZone getJdbcTimeZone() { + return jdbcTimeZone; + } + + @Override @Deprecated(forRemoval = true) + public StatelessSessionBuilder tenantIdentifier(String tenantIdentifier) { + this.tenantIdentifier = tenantIdentifier; + return null; + } + + @Override @Deprecated + public StatelessSessionBuilder statementInspector(StatementInspector statementInspector) { + this.statementInspector = statementInspector; + return this; + } + @Override public boolean isTransactionCoordinatorShared() { return shareTransactionContext; @@ -117,15 +155,22 @@ public boolean isTransactionCoordinatorShared() { @Override public TransactionCoordinator getTransactionCoordinator() { - return isTransactionCoordinatorShared() + return shareTransactionContext ? original.getTransactionCoordinator() : null; } @Override public JdbcCoordinator getJdbcCoordinator() { - return isTransactionCoordinatorShared() + return shareTransactionContext ? original.getJdbcCoordinator() : null; } + + @Override + public Transaction getTransaction() { + return shareTransactionContext + ? original.getTransaction() + : null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java index dc383f7a6190..c49c18c75f85 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java @@ -10,10 +10,12 @@ import org.hibernate.SessionEventListener; import org.hibernate.StatelessSession; import org.hibernate.StatelessSessionBuilder; -import org.hibernate.internal.SessionFactoryImpl; -import org.hibernate.internal.StatelessSessionImpl; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.StatelessSessionImplementor; +import org.hibernate.internal.CoreLogging; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; +import org.jboss.logging.Logger; import java.sql.Connection; import java.util.List; @@ -22,11 +24,13 @@ /** * @author Steve Ebersole */ -public class StatelessSessionBuilderImpl +public abstract class StatelessSessionBuilderImpl extends AbstractCommonBuilder implements StatelessSessionBuilder, SessionCreationOptions { - public StatelessSessionBuilderImpl(SessionFactoryImpl sessionFactory) { + private static final Logger LOG = CoreLogging.logger( StatelessSessionBuilderImpl.class ); + + public StatelessSessionBuilderImpl(SessionFactoryImplementor sessionFactory) { super( sessionFactory ); } @@ -40,11 +44,14 @@ protected StatelessSessionBuilder getThis() { @Override public StatelessSession openStatelessSession() { - return new StatelessSessionImpl( sessionFactory, this ); + LOG.tracef( "Opening StatelessSession [tenant=%s]", tenantIdentifier ); + return createStatelessSession(); } + protected abstract StatelessSessionImplementor createStatelessSession(); + @Override - @Deprecated + @Deprecated(forRemoval = true) public StatelessSessionBuilder tenantIdentifier(String tenantIdentifier) { this.tenantIdentifier = tenantIdentifier; return this; @@ -97,8 +104,7 @@ public Connection getConnection() { @Override public Interceptor getInterceptor() { - return SessionFactoryImpl.configuredInterceptor( interceptor, explicitNoInterceptor, - sessionFactory.getSessionFactoryOptions() ); + return configuredInterceptor(); } @Override @@ -117,12 +123,6 @@ public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() { return connectionHandlingMode; } - @Override - public String getTenantIdentifier() { - return tenantIdentifier == null ? null - : sessionFactory.getTenantIdentifierJavaType().toString( tenantIdentifier ); - } - @Override public boolean isReadOnly() { return readOnly; @@ -140,11 +140,11 @@ public Object getTenantIdentifierValue() { @Override public TimeZone getJdbcTimeZone() { - return sessionFactory.getSessionFactoryOptions().getJdbcTimeZone(); + return jdbcTimeZone; } @Override - public List getCustomSessionEventListener() { + public List getCustomSessionEventListeners() { return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java index 9fc437abdecd..9b58897854f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java @@ -37,6 +37,9 @@ public interface SessionBuilderImplementor extends SessionBuilder { @Override SessionBuilderImplementor noInterceptor(); + @Override + SessionBuilderImplementor noSessionInterceptorCreation(); + @Override SessionBuilderImplementor statementInspector(UnaryOperator operator); @@ -61,7 +64,7 @@ public interface SessionBuilderImplementor extends SessionBuilder { @Override SessionBuilderImplementor flushMode(FlushMode flushMode); - @Override + @Override @Deprecated(forRemoval = true) SessionBuilderImplementor tenantIdentifier(String tenantIdentifier); @Override diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java index 2f08c754c406..b5e88be16b33 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java @@ -30,6 +30,9 @@ public interface SharedSessionBuilderImplementor extends SharedSessionBuilder, S @Override SharedSessionBuilderImplementor noInterceptor(); + @Override + SharedSessionBuilderImplementor noSessionInterceptorCreation(); + @Override SharedSessionBuilderImplementor statementInspector(UnaryOperator operator); @@ -52,7 +55,7 @@ public interface SharedSessionBuilderImplementor extends SharedSessionBuilder, S @Override SharedSessionBuilderImplementor interceptor(); - @Override + @Override @Deprecated SharedSessionBuilderImplementor connectionReleaseMode(); @Override @@ -67,7 +70,7 @@ public interface SharedSessionBuilderImplementor extends SharedSessionBuilder, S @Override SharedSessionBuilderImplementor autoClose(); - @Override + @Override @Deprecated SharedSessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode mode); @Override @@ -79,7 +82,7 @@ public interface SharedSessionBuilderImplementor extends SharedSessionBuilder, S @Override SharedSessionBuilderImplementor flushMode(FlushMode flushMode); - @Override + @Override @Deprecated(forRemoval = true) SharedSessionBuilderImplementor tenantIdentifier(String tenantIdentifier); @Override diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java index 83bf0084cf32..43d4555b02de 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java @@ -17,7 +17,6 @@ import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails; import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; -import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlStatementLogger; @@ -60,7 +59,7 @@ public BatchImpl( this.jdbcCoordinator = jdbcCoordinator; this.statementGroup = statementGroup; - final JdbcServices jdbcServices = + final var jdbcServices = jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getJdbcServices(); sqlStatementLogger = jdbcServices.getSqlStatementLogger(); sqlExceptionHelper = jdbcServices.getSqlExceptionHelper(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java index f77fcfb7689a..7a8b8db11466 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java @@ -59,6 +59,12 @@ public SessionBuilderImplementor noInterceptor() { return this; } + @Override + public SessionBuilderImplementor noSessionInterceptorCreation() { + delegate.noSessionInterceptorCreation(); + return this; + } + @Override @Deprecated public SessionBuilderImplementor statementInspector(StatementInspector statementInspector) { delegate.statementInspector( statementInspector ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java index e947fc22a6bc..99edad561219 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java @@ -8,7 +8,6 @@ import java.util.TimeZone; import java.util.function.UnaryOperator; -import org.hibernate.engine.creation.CommonSharedBuilder; import org.hibernate.CacheMode; import org.hibernate.ConnectionAcquisitionMode; import org.hibernate.ConnectionReleaseMode; @@ -95,6 +94,12 @@ public SharedSessionBuilder noInterceptor() { return this; } + @Override + public SharedSessionBuilder noSessionInterceptorCreation() { + delegate.noSessionInterceptorCreation(); + return this; + } + @Override @Deprecated public SharedSessionBuilder statementInspector(StatementInspector statementInspector) { delegate.statementInspector( statementInspector ); @@ -108,13 +113,13 @@ public SharedSessionBuilder statementInspector(UnaryOperator operator) { } @Override - public CommonSharedBuilder statementInspector() { + public SharedSessionBuilder statementInspector() { delegate.statementInspector(); return this; } @Override - public CommonSharedBuilder noStatementInspector() { + public SharedSessionBuilder noStatementInspector() { delegate.noStatementInspector(); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index ece114ba9ab9..90c3b1c3e636 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -386,6 +386,11 @@ public boolean shouldAutoJoinTransaction() { return delegate.shouldAutoJoinTransaction(); } + @Override + public boolean isAutoCloseSessionEnabled() { + return delegate.isAutoCloseSessionEnabled(); + } + @Override public LoadQueryInfluencers getLoadQueryInfluencers() { return delegate.getLoadQueryInfluencers(); @@ -432,6 +437,11 @@ public Transaction accessTransaction() { return delegate.accessTransaction(); } + @Override + public Transaction getCurrentTransaction() { + return delegate.getCurrentTransaction(); + } + @Override public Transaction beginTransaction() { return delegate.beginTransaction(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java index 0a39869ab02c..6544763a5af5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java @@ -423,4 +423,9 @@ public EventListenerRegistry getEventListenerRegistry() { public TypedQueryReference addNamedQuery(String name, TypedQuery query) { return delegate.addNamedQuery( name, query ); } + + @Override + public Object resolveTenantIdentifier() { + return delegate.resolveTenantIdentifier(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java index 1f5625e7123d..230850cd2d4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java @@ -186,6 +186,15 @@ default JpaMetamodel getJpaMetamodel() { //todo make a Service ? CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver(); + /** + * Object the current tenant identifier using the + * {@linkplain #getCurrentTenantIdentifierResolver() resolver}. + * + * @since 7.2 + */ + @Incubating + Object resolveTenantIdentifier(); + /** * The {@link JavaType} to use for a tenant identifier. * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java index daefd65cff10..084e35f01db5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java @@ -78,6 +78,12 @@ default TransactionCompletionCallbacks getTransactionCompletionCallbacks() { return getActionQueue(); } + /** + * Should this session be automatically closed after the current + * transaction completes? + */ + boolean isAutoCloseSessionEnabled(); + @Override Object instantiate(EntityPersister persister, Object id) throws HibernateException; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java index 715f13f700e9..dba79234c803 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java @@ -75,12 +75,13 @@ public interface SharedSessionContractImplementor /** * Obtain the {@linkplain SessionFactoryImplementor factory} which created this session. */ + @Override SessionFactoryImplementor getFactory(); /** * Obtain the {@linkplain SessionFactoryImplementor factory} which created this session. */ -// @Override + @Override default SessionFactoryImplementor getSessionFactory() { return getFactory(); } @@ -246,6 +247,15 @@ default void checkTransactionNeededForUpdateOperation(String exceptionMessage) { */ Transaction accessTransaction(); + /** + * The current {@link Transaction} object associated with this session, + * if it has already been created, or {@code null} otherwise. + * + * @since 7.2 + */ + @Incubating + Transaction getCurrentTransaction(); + /** * Access to register callbacks for transaction completion processing. * @@ -387,6 +397,7 @@ default String bestGuessEntityName(Object object, EntityEntry entry) { * * @return The flush mode */ + @Override FlushMode getHibernateFlushMode(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java index e8ececa07237..2b709017cc41 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java @@ -17,6 +17,7 @@ import org.hibernate.Interceptor; import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.SharedSessionBuilder; import org.hibernate.SharedSessionContract; import org.hibernate.SharedStatelessSessionBuilder; import org.hibernate.Transaction; @@ -721,4 +722,14 @@ public void afterObtainConnection(Connection connection) throws SQLException { public void beforeReleaseConnection(Connection connection) throws SQLException { delegate.beforeReleaseConnection( connection ); } + + @Override + public Transaction getCurrentTransaction() { + return delegate.getCurrentTransaction(); + } + + @Override + public SharedSessionBuilder sessionWithOptions() { + return delegate.sessionWithOptions(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 02371d733036..251e04f1b21b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -18,8 +18,8 @@ import org.hibernate.HibernateException; import org.hibernate.Interceptor; import org.hibernate.LockMode; -import org.hibernate.SessionEventListener; import org.hibernate.SessionException; +import org.hibernate.SharedSessionBuilder; import org.hibernate.SharedStatelessSessionBuilder; import org.hibernate.Transaction; import org.hibernate.UnknownEntityTypeException; @@ -29,6 +29,8 @@ import org.hibernate.cache.spi.CacheTransactionSynchronization; import org.hibernate.dialect.Dialect; import org.hibernate.engine.creation.internal.SessionCreationOptions; +import org.hibernate.engine.creation.internal.SessionCreationOptionsAdaptor; +import org.hibernate.engine.creation.internal.SharedSessionBuilderImpl; import org.hibernate.engine.creation.internal.SharedSessionCreationOptions; import org.hibernate.engine.creation.internal.SharedStatelessSessionBuilderImpl; import org.hibernate.engine.internal.SessionEventListenerManagerImpl; @@ -42,7 +44,9 @@ import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionEventListenerManager; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.StatelessSessionImplementor; import org.hibernate.engine.transaction.internal.TransactionImpl; import org.hibernate.event.monitor.spi.EventMonitor; import org.hibernate.graph.GraphSemantic; @@ -187,7 +191,9 @@ public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreation factoryOptions = factory.getSessionFactoryOptions(); jdbcServices = factory.getJdbcServices(); - cacheTransactionSynchronization = factory.getCache().getRegionFactory().createTransactionContext( this ); + cacheTransactionSynchronization = + factory.getCache().getRegionFactory() + .createTransactionContext( this ); tenantIdentifier = getTenantId( factoryOptions, options ); readOnly = options.isReadOnly(); @@ -204,9 +210,9 @@ public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreation final var statementInspector = interpret( options.getStatementInspector() ); - isTransactionCoordinatorShared = isTransactionCoordinatorShared( options ); - if ( isTransactionCoordinatorShared ) { - final var sharedOptions = (SharedSessionCreationOptions) options; + if ( options instanceof SharedSessionCreationOptions sharedOptions + && sharedOptions.isTransactionCoordinatorShared() ) { + isTransactionCoordinatorShared = true; if ( options.getConnection() != null ) { throw new SessionException( "Cannot simultaneously share transaction context and specify connection" ); } @@ -221,6 +227,7 @@ public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreation addSharedSessionTransactionObserver( transactionCoordinator ); } else { + isTransactionCoordinatorShared = false; autoJoinTransactions = options.shouldAutoJoinTransactions(); connectionHandlingMode = options.getPhysicalConnectionHandlingMode(); jdbcSessionContext = createJdbcSessionContext( statementInspector ); @@ -238,12 +245,23 @@ final SessionFactoryOptions getSessionFactoryOptions() { @Override public SharedStatelessSessionBuilder statelessWithOptions() { - return new SharedStatelessSessionBuilderImpl( this ); + return new SharedStatelessSessionBuilderImpl( this ) { + @Override + protected StatelessSessionImplementor createStatelessSession() { + return new StatelessSessionImpl( factory, + new SessionCreationOptionsAdaptor( factory, this ) ); + } + }; } - private static boolean isTransactionCoordinatorShared(SessionCreationOptions options) { - return options instanceof SharedSessionCreationOptions sharedSessionCreationOptions - && sharedSessionCreationOptions.isTransactionCoordinatorShared(); + @Override + public SharedSessionBuilder sessionWithOptions() { + return new SharedSessionBuilderImpl( this ) { + @Override + protected SessionImplementor createSession() { + return new SessionImpl( factory, this ); + } + }; } protected final void setUpMultitenancy(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) { @@ -315,7 +333,7 @@ void checkNotReadOnly() { private static SessionEventListenerManager createSessionEventsManager( SessionFactoryOptions factoryOptions, SessionCreationOptions options) { - final var customListeners = options.getCustomSessionEventListener(); + final var customListeners = options.getCustomSessionEventListeners(); return customListeners == null ? new SessionEventListenerManagerImpl( factoryOptions.buildSessionEventListeners() ) : new SessionEventListenerManagerImpl( customListeners ); @@ -502,7 +520,8 @@ public void close() { } try { - if ( shouldCloseJdbcCoordinatorOnClose( isTransactionCoordinatorShared ) ) { + if ( !isTransactionCoordinatorShared ) { + checkBeforeClosingJdbcCoordinator(); jdbcCoordinator.close(); } } @@ -518,8 +537,7 @@ protected void setClosed() { cleanupOnClose(); } - protected boolean shouldCloseJdbcCoordinatorOnClose(boolean isTransactionCoordinatorShared) { - return true; + protected void checkBeforeClosingJdbcCoordinator() { } protected void cleanupOnClose() { @@ -685,6 +703,7 @@ protected void delayedAfterCompletion() { } } + @Override public Transaction getCurrentTransaction() { return currentHibernateTransaction; } @@ -1719,13 +1738,15 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound jdbcServices = factory.getJdbcServices(); //TODO: this isn't quite right, see createSessionEventsManager() - final SessionEventListener[] baseline = factoryOptions.buildSessionEventListeners(); + final var baseline = factoryOptions.buildSessionEventListeners(); sessionEventsManager = new SessionEventListenerManagerImpl( baseline ); jdbcSessionContext = createJdbcSessionContext( (StatementInspector) ois.readObject() ); jdbcCoordinator = JdbcCoordinatorImpl.deserialize( ois, this ); - cacheTransactionSynchronization = factory.getCache().getRegionFactory().createTransactionContext( this ); + cacheTransactionSynchronization = + factory.getCache().getRegionFactory() + .createTransactionContext( this ); transactionCoordinator = factory.transactionCoordinatorBuilder.buildTransactionCoordinator( jdbcCoordinator, this ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index a22da079aa7d..7a620506ccf0 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -63,6 +63,7 @@ import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.StatelessSessionImplementor; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.event.monitor.internal.EmptyEventMonitor; import org.hibernate.event.monitor.spi.EventMonitor; @@ -542,12 +543,22 @@ public Session getCurrentSession() { @Override public SessionBuilderImplementor withOptions() { - return new SessionBuilderImpl( this ); + return new SessionBuilderImpl( this ) { + @Override + protected SessionImplementor createSession() { + return new SessionImpl( (SessionFactoryImpl) sessionFactory, this ); + } + }; } @Override public StatelessSessionBuilder withStatelessOptions() { - return new StatelessSessionBuilderImpl( this ); + return new StatelessSessionBuilderImpl( this ) { + @Override + protected StatelessSessionImplementor createStatelessSession() { + return new StatelessSessionImpl( (SessionFactoryImpl) sessionFactory, this ); + } + }; } @Override @@ -1053,46 +1064,6 @@ public EntityNotFoundDelegate getEntityNotFoundDelegate() { return sessionFactoryOptions.getEntityNotFoundDelegate(); } - /** - * @deprecated use {@link #configuredInterceptor(Interceptor, boolean, SessionFactoryOptions)} - */ - @Deprecated - public static Interceptor configuredInterceptor(Interceptor interceptor, SessionFactoryOptions options) { - return configuredInterceptor( interceptor, false, options ); - } - - public static Interceptor configuredInterceptor(Interceptor interceptor, boolean explicitNoInterceptor, SessionFactoryOptions options) { - // NOTE: DO NOT return EmptyInterceptor.INSTANCE from here as a "default for the Session" - // we "filter" that one out here. The return from here should represent the - // explicitly configured Interceptor (if one). Return null from here instead; - // Session will handle it - - if ( interceptor != null && interceptor != EmptyInterceptor.INSTANCE ) { - return interceptor; - } - - // prefer the SessionFactory-scoped interceptor, prefer that to any Session-scoped interceptor prototype - final var optionsInterceptor = options.getInterceptor(); - if ( optionsInterceptor != null && optionsInterceptor != EmptyInterceptor.INSTANCE ) { - return optionsInterceptor; - } - - // If explicitly asking for no interceptor and there is no SessionFactory-scoped interceptor, then - // no need to inherit from the configured stateless session ones. - if ( explicitNoInterceptor ) { - return null; - } - - // then check the Session-scoped interceptor prototype - final var statelessInterceptorImplementorSupplier = - options.getStatelessInterceptorImplementorSupplier(); - if ( statelessInterceptorImplementorSupplier != null ) { - return statelessInterceptorImplementorSupplier.get(); - } - - return null; - } - public Object resolveTenantIdentifier() { final var resolver = getCurrentTenantIdentifierResolver(); return resolver != null diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 7b792c645ff0..f81f33320029 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -26,7 +26,6 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.creation.internal.SessionCreationOptions; -import org.hibernate.engine.creation.internal.SharedSessionBuilderImpl; import org.hibernate.engine.creation.internal.SharedSessionCreationOptions; import org.hibernate.engine.internal.PersistenceContexts; import org.hibernate.engine.spi.ActionQueue; @@ -326,11 +325,6 @@ private Map getDefaultProperties() { return getSessionFactoryOptions().getDefaultSessionProperties(); } - @Override - public SharedSessionBuilder sessionWithOptions() { - return new SharedSessionBuilderImpl( this ); - } - @Override public void clear() { checkOpen(); @@ -428,20 +422,14 @@ private boolean isTransactionActiveAndNotMarkedForRollback() { } @Override - protected boolean shouldCloseJdbcCoordinatorOnClose(boolean isTransactionCoordinatorShared) { - if ( isTransactionCoordinatorShared ) { - final var actionQueue = getActionQueue(); - if ( actionQueue.hasBeforeTransactionActions() || actionQueue.hasAfterTransactionActions() ) { - LOG.warn( "Closing shared session with unprocessed transaction completion actions" ); - } + protected void checkBeforeClosingJdbcCoordinator() { + final var actionQueue = getActionQueue(); + if ( actionQueue.hasBeforeTransactionActions() || actionQueue.hasAfterTransactionActions() ) { + LOG.warn( "Closing shared session with unprocessed transaction completion actions" ); } - return !isTransactionCoordinatorShared; } - /** - * Should this session be automatically closed after the current - * transaction completes? - */ + @Override public boolean isAutoCloseSessionEnabled() { return autoClose; } @@ -489,9 +477,9 @@ else if ( isClosed() ) { } else { // JPA technically requires that this be a PersistentUnityTransactionType#JTA to work, - // but we do not assert that here... - //return isAutoCloseSessionEnabled() && getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta(); + // but we do not assert that here: return isAutoCloseSessionEnabled(); + // && getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta(); } } @@ -2097,12 +2085,13 @@ private boolean mustFlushBeforeCompletion() { } private boolean isTransactionFlushable() { - if ( getCurrentTransaction() == null ) { + final var currentTransaction = getCurrentTransaction(); + if ( currentTransaction == null ) { // assume it is flushable - CMT, auto-commit, etc return true; } else { - final TransactionStatus status = getCurrentTransaction().getStatus(); + final TransactionStatus status = currentTransaction.getStatus(); return status == TransactionStatus.ACTIVE || status == TransactionStatus.COMMITTING; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 66c550464997..2cf5fcf7307b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -8,13 +8,10 @@ import jakarta.persistence.PersistenceException; import jakarta.transaction.SystemException; import org.hibernate.AssertionFailure; -import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.HibernateException; -import org.hibernate.Interceptor; import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.SessionEventListener; import org.hibernate.SessionException; import org.hibernate.StatelessSession; import org.hibernate.TransientObjectException; @@ -27,7 +24,6 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.StatelessSessionImplementor; import org.hibernate.engine.spi.TransactionCompletionCallbacks; @@ -68,14 +64,10 @@ import org.hibernate.loader.internal.CacheLoadHelper; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; -import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.stat.spi.StatisticsImplementor; -import java.sql.Connection; import java.util.List; import java.util.Set; -import java.util.TimeZone; import java.util.function.BiConsumer; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; @@ -142,25 +134,6 @@ public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions o setJdbcBatchSize( 0 ); } - /** - * Form used when creating a "shared" stateless session. - */ - public StatelessSessionImpl(SessionFactoryImplementor factory, CommonSharedSessionCreationOptions options) { - super( - (SessionFactoryImpl) factory, - CommonSharedSessionCreationOptionsWrapper.wrapOptions( (SessionFactoryImpl) factory, options ) - ); - connectionProvided = false; - transactionCompletionCallbacks = new TransactionCompletionCallbacksImpl( this ); - temporaryPersistenceContext = createPersistenceContext( this ); - influencers = new LoadQueryInfluencers( getFactory() ); - eventListenerGroups = factory.getEventListenerGroups(); - setUpMultitenancy( factory, influencers ); - // a nonzero batch size forces use of write-behind - // therefore ignore the value of hibernate.jdbc.batch_size - setJdbcBatchSize( 0 ); - } - @Override public boolean shouldAutoJoinTransaction() { return true; @@ -1514,109 +1487,4 @@ public Integer getBatchSize() { } } - /** - * Wraps a CommonSharedSessionCreationOptions as a SessionCreationOptions to pass - * to AbstractSharedSessionContract during construction. - * - * @param factory The SessionFactory - * @param options The CommonSharedSessionCreationOptions being wrapped. - */ - private record CommonSharedSessionCreationOptionsWrapper( - SessionFactoryImplementor factory, - CommonSharedSessionCreationOptions options) - implements SessionCreationOptions { - - private static SessionCreationOptions wrapOptions(SessionFactoryImpl factory, CommonSharedSessionCreationOptions options) { - return new CommonSharedSessionCreationOptionsWrapper( factory, options ); - } - - @Override - public Interceptor getInterceptor() { - return options.getInterceptor(); - } - - @Override - public StatementInspector getStatementInspector() { - return options.getStatementInspector(); - } - - @Override - public Object getTenantIdentifierValue() { - return options.getTenantIdentifierValue(); - } - - @Override - public boolean isReadOnly() { - return options.isReadOnly(); - } - - @Override - public CacheMode getInitialCacheMode() { - return options.getInitialCacheMode(); - } - - @Override - public boolean shouldAutoJoinTransactions() { - return true; - } - - @Override - public FlushMode getInitialSessionFlushMode() { - return FlushMode.ALWAYS; - } - - @Override - public boolean isSubselectFetchEnabled() { - return false; - } - - @Override - public int getDefaultBatchFetchSize() { - return -1; - } - - @Override - public boolean shouldAutoClose() { - return false; - } - - @Override - public boolean shouldAutoClear() { - return false; - } - - @Override - public Connection getConnection() { - return null; - } - - @Override - public boolean isIdentifierRollbackEnabled() { - // identifier rollback not yet implemented for StatelessSessions - return false; - } - - @Override - public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() { - return factory.getSessionFactoryOptions().getPhysicalConnectionHandlingMode(); - } - - @Override - public String getTenantIdentifier() { - final Object tenantIdentifier = getTenantIdentifierValue(); - return tenantIdentifier == null - ? null - : factory.getTenantIdentifierJavaType().toString( tenantIdentifier ); - } - - @Override - public TimeZone getJdbcTimeZone() { - return factory.getSessionFactoryOptions().getJdbcTimeZone(); - } - - @Override - public List getCustomSessionEventListener() { - return null; - } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SessionWithSharedConnectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SessionWithSharedConnectionTest.java index 79d5225039b5..97e29f5cd722 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SessionWithSharedConnectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SessionWithSharedConnectionTest.java @@ -15,7 +15,6 @@ import org.hibernate.internal.SessionImpl; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.resource.jdbc.spi.JdbcSessionOwner; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.SessionFactory; @@ -27,13 +26,13 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Steve Ebersole @@ -57,16 +56,14 @@ public void testSharedTransactionContextSessionClosing(SessionFactoryScope scope // secondSession.createCriteria( IrrelevantEntity.class ).list(); //the list should have registered and then released a JDBC resource - assertFalse( - ((SessionImplementor) secondSession) - .getJdbcCoordinator().getLogicalConnection().getResourceRegistry() - .hasRegisteredResources() - ); + assertFalse( ((SessionImplementor) secondSession) + .getJdbcCoordinator().getLogicalConnection().getResourceRegistry() + .hasRegisteredResources() ); assertTrue( session.isOpen() ); assertTrue( secondSession.isOpen() ); - assertSame( session.getTransaction(), secondSession.getTransaction() ); + Assertions.assertSame( session.getTransaction(), secondSession.getTransaction() ); session.getTransaction().commit(); @@ -232,13 +229,13 @@ public boolean requiresPostCommitHandling(EntityPersister persister) { session.getTransaction().commit(); //both entities should have their names updated to the postCommitMessage value - assertEquals(postCommitMessage, irrelevantEntityMainSession.getName()); - assertEquals(postCommitMessage, irrelevantEntitySecondarySession.getName()); + assertEquals( postCommitMessage, irrelevantEntityMainSession.getName() ); + assertEquals( postCommitMessage, irrelevantEntitySecondarySession.getName() ); } @Test @JiraKey( value = "HHH-7239" ) - public void testChildSessionTwoTransactions(SessionFactoryScope scope) throws Exception { + public void testChildSessionTwoTransactions(SessionFactoryScope scope) { Session session = scope.getSessionFactory().openSession(); session.getTransaction().begin(); @@ -262,10 +259,10 @@ public void testChildSessionTwoTransactions(SessionFactoryScope scope) throws Ex @Test @JiraKey(value = "HHH-11830") - public void testSharedSessionTransactionObserver(SessionFactoryScope scope) throws Exception { + public void testSharedSessionTransactionObserver(SessionFactoryScope scope) { scope.inTransaction( session -> { Field field = null; - Class clazz = ( (JdbcSessionOwner) session ).getTransactionCoordinator().getClass(); + Class clazz = session.getTransactionCoordinator().getClass(); while ( clazz != null ) { try { field = clazz.getDeclaredField( "observers" ); @@ -279,12 +276,12 @@ public void testSharedSessionTransactionObserver(SessionFactoryScope scope) thro throw new IllegalStateException( e ); } } - assertNotNull( "Observers field was not found", field ); + assertNotNull( field, "Observers field was not found" ); try { //Some of these collections could be lazily initialize: check for null before invoking size() - final Collection collection = (Collection) field.get( session.getTransactionCoordinator() ); - assertTrue( collection == null || collection.size() == 0 ); + final Collection collection = (Collection) field.get( session.getTransactionCoordinator() ); + assertTrue( collection == null || collection.isEmpty() ); //open secondary sessions with managed options and immediately close Session secondarySession; @@ -296,18 +293,14 @@ public void testSharedSessionTransactionObserver(SessionFactoryScope scope) thro .openSession(); //when the shared session is opened it should register an observer - assertEquals( - 1, - ( (Collection) field.get( session.getTransactionCoordinator() ) ).size() - ); + assertEquals( 1, + ( (Collection) field.get( session.getTransactionCoordinator() ) ).size() ); //observer should be released secondarySession.close(); - assertEquals( - 0, - ( (Collection) field.get( session.getTransactionCoordinator() ) ).size() - ); + assertEquals( 0, + ( (Collection) field.get( session.getTransactionCoordinator() ) ).size() ); } } catch (Exception e) { diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java index 724ee86256d3..babdbb77ba0b 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java @@ -18,9 +18,11 @@ import org.hibernate.envers.internal.revisioninfo.RevisionInfoGenerator; import org.hibernate.envers.internal.synchronization.work.AuditWorkUnit; import org.hibernate.envers.tools.Pair; -import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.jboss.logging.Logger; +import static org.hibernate.ConnectionAcquisitionMode.AS_NEEDED; +import static org.hibernate.ConnectionReleaseMode.AFTER_TRANSACTION; + /** * @author Adam Warski (adam at warski dot org) * @author Chris Cranford @@ -148,7 +150,7 @@ public void doBeforeTransactionCompletion(SharedSessionContractImplementor sessi if ( statelessSession.isClosed() ) { try (StatelessSessionImplementor temporarySession = (StatelessSessionImplementor) statelessSession.statelessWithOptions() .connection() - .noInterceptor() + .noSessionInterceptorCreation() .open()) { executeInStatelessSession( temporarySession ); } @@ -163,8 +165,8 @@ else if ( FlushMode.MANUAL.equals( session.getHibernateFlushMode() ) || session. try (SessionImplementor temporarySession = (SessionImplementor) statefulSession.sessionWithOptions() .connection() .autoClose( false ) - .connectionHandlingMode( PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION ) - .noInterceptor() + .connectionHandling( AS_NEEDED, AFTER_TRANSACTION ) + .noSessionInterceptorCreation() .openSession()) { executeInSession( temporarySession ); temporarySession.flush(); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java index 5548bff3bc00..0529a67c6454 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java @@ -66,10 +66,10 @@ public void initData() throws Exception { @Test public void testInterceptorInvocations() throws Exception { - // Expect the interceptor to have been created once and invoked twice, once for the original session - // and follow-up for the Envers temporary session. + // The interceptor should only be created once and should only be invoked twice + // Once for the original session, and follow-up for the Envers temporary session final Map invocationMap = TestInterceptor.getBeforeCompletionCallbacks(); assertEquals( 1, invocationMap.size() ); - assertEquals( invocationMap.values().stream().filter( v -> v == 2 ).count(), 1 ); + invocationMap.values().forEach( c -> assertEquals( 2, c.intValue() ) ); } } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java index 466f991e5683..15f274bd640b 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java @@ -63,10 +63,10 @@ public void initData() throws Exception { } @Test - public void testInterceptorInvocations() throws Exception { - // The interceptor should only be created once and should only be invoked once. + public void testInterceptorInvocations() { + // The interceptor should be created one and should only be invoked once final Map invocationMap = TestInterceptor.getBeforeCompletionCallbacks(); assertEquals( 1, invocationMap.size() ); - assertEquals( invocationMap.values().stream().filter( v -> v == 1 ).count(), 1 ); + invocationMap.values().forEach( c -> assertEquals( 1, c.intValue() ) ); } }