clean up the JdbcSessionContext SPI + related code

- encapsulate stuff better within JdbcSessionContext
- fix lots of warnings
- deprecate stuff
This commit is contained in:
Gavin 2023-01-01 13:38:57 +01:00 committed by Gavin King
parent 689cca1963
commit 366208924f
23 changed files with 419 additions and 345 deletions

View File

@ -1133,7 +1133,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
@Override
public boolean isPreferUserTransaction() {
return this.preferUserTransaction;
return preferUserTransaction;
}
@Override

View File

@ -2180,7 +2180,7 @@ public interface AvailableSettings {
* transaction timeout handled by a background reaper thread. The ability
* to handle this situation requires checking the Thread ID every time
* Session is called. This can certainly have performance considerations.
*
* <p>
* Default is {@code true} (enabled).
*
* @see org.hibernate.boot.SessionFactoryBuilder#applyJtaTrackingByThread(boolean)

View File

@ -68,11 +68,7 @@ public class BatchImpl implements Batch {
this.jdbcCoordinator = jdbcCoordinator;
this.statementGroup = statementGroup;
final JdbcServices jdbcServices = jdbcCoordinator.getJdbcSessionOwner()
.getJdbcSessionContext()
.getSessionFactory()
.getFastSessionServices().jdbcServices;
final JdbcServices jdbcServices = jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getJdbcServices();
this.sqlStatementLogger = jdbcServices.getSqlStatementLogger();
this.sqlExceptionHelper = jdbcServices.getSqlExceptionHelper();

View File

@ -19,9 +19,7 @@ import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.TransactionException;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
import org.hibernate.engine.jdbc.spi.InvalidatableWrapper;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
@ -31,7 +29,6 @@ import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
import org.hibernate.engine.jdbc.spi.ResultSetReturn;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.StatementPreparer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jdbc.WorkExecutor;
@ -44,6 +41,8 @@ import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransaction;
import static org.hibernate.ConnectionReleaseMode.AFTER_STATEMENT;
/**
* Standard implementation of {@link JdbcCoordinator}.
*
@ -72,7 +71,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
private boolean releasesEnabled = true;
/**
* Constructs a JdbcCoordinatorImpl
* Constructs a {@code JdbcCoordinatorImpl}
*
* @param userSuppliedConnection The user supplied connection (may be null)
*/
@ -107,9 +106,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
this.logicalConnection = logicalConnection;
this.isUserSuppliedConnection = isUserSuppliedConnection;
this.owner = owner;
this.jdbcServices = owner.getJdbcSessionContext()
.getServiceRegistry()
.getService( JdbcServices.class );
this.jdbcServices = owner.getJdbcSessionContext().getJdbcServices();
}
@Override
@ -117,14 +114,10 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
return logicalConnection;
}
protected SessionFactoryImplementor sessionFactory() {
return this.owner.getJdbcSessionContext().getSessionFactory();
}
/**
* Access to the SqlExceptionHelper
* Access to the {@link SqlExceptionHelper}
*
* @return The SqlExceptionHelper
* @return The {@code SqlExceptionHelper}
*/
public SqlExceptionHelper sqlExceptionHelper() {
return jdbcServices.getSqlExceptionHelper();
@ -181,8 +174,8 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
}
}
final BatchBuilder batchBuilder = sessionFactory().getFastSessionServices().batchBuilder;
currentBatch = batchBuilder.buildBatch( key, batchSize, statementGroupSupplier, this );
currentBatch = owner.getJdbcSessionContext().getBatchBuilder()
.buildBatch( key, batchSize, statementGroupSupplier, this );
return currentBatch;
}
@ -262,7 +255,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
public void afterStatementExecution() {
final ConnectionReleaseMode connectionReleaseMode = getLogicalConnection().getConnectionHandlingMode().getReleaseMode();
LOG.tracev( "Starting after statement execution processing [{0}]", connectionReleaseMode );
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
if ( connectionReleaseMode == AFTER_STATEMENT ) {
if ( ! releasesEnabled ) {
LOG.debug( "Skipping aggressive release due to manual disabling" );
return;
@ -278,38 +271,18 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
@Override
public void afterTransaction() {
transactionTimeOutInstant = -1;
ConnectionReleaseMode connectionReleaseMode = getLogicalConnection().getConnectionHandlingMode().getReleaseMode();
if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ||
connectionReleaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ||
connectionReleaseMode == ConnectionReleaseMode.BEFORE_TRANSACTION_COMPLETION ) {
this.logicalConnection.afterTransaction();
switch ( getLogicalConnection().getConnectionHandlingMode().getReleaseMode() ) {
case AFTER_STATEMENT:
case AFTER_TRANSACTION:
case BEFORE_TRANSACTION_COMPLETION:
logicalConnection.afterTransaction();
}
}
private void releaseResources() {
getLogicalConnection().getResourceRegistry().releaseResources();
}
private boolean hasRegisteredResources() {
return getLogicalConnection().getResourceRegistry().hasRegisteredResources();
}
private ConnectionReleaseMode determineConnectionReleaseMode(
JdbcConnectionAccess jdbcConnectionAccess,
boolean isUserSuppliedConnection,
ConnectionReleaseMode connectionReleaseMode) {
if ( isUserSuppliedConnection ) {
return ConnectionReleaseMode.ON_CLOSE;
}
else if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT &&
! jdbcConnectionAccess.supportsAggressiveRelease() ) {
LOG.debug( "Connection provider reports to not support aggressive release; overriding" );
return ConnectionReleaseMode.AFTER_TRANSACTION;
}
else {
return connectionReleaseMode;
}
}
@Override
public <T> T coordinateWork(WorkExecutorVisitable<T> work) {
final Connection connection = getLogicalConnection().getPhysicalConnection();
@ -325,7 +298,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
@Override
public boolean isReadyForSerialization() {
return this.isUserSuppliedConnection
return isUserSuppliedConnection
? ! getLogicalConnection().isPhysicallyConnected()
: ! hasRegisteredResources();
}
@ -349,19 +322,20 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
lastQuery.cancel();
}
}
catch (SQLException sqle) {
SqlExceptionHelper sqlExceptionHelper = jdbcServices.getSqlExceptionHelper();
//Should always be non-null, but to make sure as the implementation is lazy:
if ( sqlExceptionHelper == null ) {
sqlExceptionHelper = new SqlExceptionHelper( false );
}
throw sqlExceptionHelper.convert( sqle, "Cannot cancel query" );
catch ( SQLException sqle ) {
throw safeSqlExceptionHelper().convert( sqle, "Cannot cancel query" );
}
finally {
lastQuery = null;
}
}
private SqlExceptionHelper safeSqlExceptionHelper() {
final SqlExceptionHelper sqlExceptionHelper = sqlExceptionHelper();
//Should always be non-null, but to make sure as the implementation is lazy:
return sqlExceptionHelper == null ? new SqlExceptionHelper( false ) : sqlExceptionHelper;
}
@Override
public void enableReleases() {
releasesEnabled = true;
@ -439,7 +413,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
@Override
public boolean isActive() {
return !sessionFactory().isClosed();
return owner.getJdbcSessionContext().isActive();
}
@Override
@ -449,8 +423,8 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
@Override
public void beforeTransactionCompletion() {
this.owner.beforeTransactionCompletion();
this.logicalConnection.beforeTransactionCompletion();
owner.beforeTransactionCompletion();
logicalConnection.beforeTransactionCompletion();
}
@Override
@ -461,7 +435,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
@Override
public JdbcSessionOwner getJdbcSessionOwner() {
return this.owner;
return owner;
}
@Override
@ -491,7 +465,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
* @param ois The stream into which to write our state
* @param owner The Jdbc Session owner which owns the JdbcCoordinatorImpl to be deserialized.
*
* @return The deserialized JdbcCoordinatorImpl
* @return The deserialized {@code JdbcCoordinatorImpl}
*
* @throws IOException Trouble accessing the stream
* @throws ClassNotFoundException Trouble reading the stream
@ -500,7 +474,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
ObjectInputStream ois,
JdbcSessionOwner owner) throws IOException, ClassNotFoundException {
final boolean isUserSuppliedConnection = ois.readBoolean();
LogicalConnectionImplementor logicalConnection;
final LogicalConnectionImplementor logicalConnection;
if ( isUserSuppliedConnection ) {
logicalConnection = LogicalConnectionProvidedImpl.deserialize( ois );
}

View File

@ -11,11 +11,11 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.AssertionFailure;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
/**
@ -138,8 +138,7 @@ public class MutationStatementPreparerImpl implements MutationStatementPreparer
return jdbcServices.getSqlExceptionHelper();
}
protected final SessionFactoryOptions settings() {
//noinspection resource
return jdbcCoordinator.sessionFactory().getSessionFactoryOptions();
protected final JdbcSessionContext settings() {
return jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext();
}
}

View File

@ -14,11 +14,11 @@ import java.sql.Statement;
import org.hibernate.AssertionFailure;
import org.hibernate.ScrollMode;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.StatementPreparer;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
/**
@ -42,8 +42,8 @@ class StatementPreparerImpl implements StatementPreparer {
this.jdbcServices = jdbcServices;
}
protected final SessionFactoryOptions settings() {
return jdbcCoordinator.sessionFactory().getSessionFactoryOptions();
protected final JdbcSessionContext settings() {
return jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext();
}
protected final Connection connection() {
@ -214,8 +214,8 @@ class StatementPreparerImpl implements StatementPreparer {
}
private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
if ( settings().getJdbcFetchSize() != null ) {
statement.setFetchSize( settings().getJdbcFetchSize() );
if ( settings().getFetchSizeOrNull() != null ) {
statement.setFetchSize( settings().getFetchSizeOrNull() );
}
}

View File

@ -16,30 +16,31 @@ import org.hibernate.service.Service;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor;
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
import org.hibernate.sql.exec.spi.JdbcOperationQueryMutation;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
/**
* Contract for services around JDBC operations. These represent shared resources, aka not varied by session/use.
* Provides access to services related to JDBC operations.
* <p>
* These services represent shared resources that do not vary by session.
*
* @author Steve Ebersole
*/
public interface JdbcServices extends Service {
/**
* Obtain the JdbcEnvironment backing this JdbcServices instance.
* Obtain the {@link JdbcEnvironment} backing this {@code JdbcServices} instance.
*/
JdbcEnvironment getJdbcEnvironment();
/**
* Obtain a JdbcConnectionAccess usable from bootstrap actions
* (hbm2ddl.auto, Dialect resolution, etc).
* Obtain a {@link JdbcConnectionAccess} usable from bootstrap actions
* (hbm2ddl.auto, {@code Dialect} resolution, etc).
*/
JdbcConnectionAccess getBootstrapJdbcConnectionAccess();
/**
* Obtain the dialect of the database.
*
* @return The database dialect.
*/
Dialect getDialect();
@ -60,15 +61,19 @@ public interface JdbcServices extends Service {
/**
* Obtain information about supported behavior reported by the JDBC driver.
* <p>
* Yuck, yuck, yuck! Much prefer this to be part of a "basic settings" type object.
* Yuck, yuck, yuck! Much prefer this to be part of a "basic settings" type object.
*
* @return The extracted database metadata, oddly enough :)
*/
ExtractedDatabaseMetaData getExtractedMetaDataSupport();
/**
* Create an instance of a {@link LobCreator} appropriate for the current environment, mainly meant to account for
* variance between JDBC 4 (&lt;= JDK 1.6) and JDBC3 (&gt;= JDK 1.5).
* Create an instance of a {@link LobCreator} appropriate for the current environment,
* mainly meant to account for variance between:
* <ul>
* <li>JDBC 4 (&lt;= JDK 1.6) and
* <li>JDBC 3 (&gt;= JDK 1.5).
* </ul>
*
* @param lobCreationContext The context in which the LOB is being created
* @return The LOB creator.
@ -76,12 +81,15 @@ public interface JdbcServices extends Service {
LobCreator getLobCreator(LobCreationContext lobCreationContext);
/**
* Access the executor for {@link JdbcOperationQuerySelect} operations
* Access the executor for {@link JdbcOperationQuerySelect} operations.
*/
default JdbcSelectExecutor getJdbcSelectExecutor() {
return JdbcSelectExecutorStandardImpl.INSTANCE;
}
/**
* Access the executor for {@link JdbcOperationQueryMutation} operations.
*/
default JdbcMutationExecutor getJdbcMutationExecutor() {
return StandardJdbcMutationExecutor.INSTANCE;
}

View File

@ -226,7 +226,19 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
private JdbcSessionContextImpl createJdbcSessionContext(StatementInspector statementInspector) {
return new JdbcSessionContextImpl(this, statementInspector, connectionHandlingMode, fastSessionServices );
return new JdbcSessionContextImpl(
factory,
statementInspector,
connectionHandlingMode,
fastSessionServices.jdbcServices,
fastSessionServices.batchBuilder,
// TODO: this object is deprecated and should be removed
new JdbcObserverImpl(
fastSessionServices.getDefaultJdbcObserver(),
sessionEventsManager,
() -> jdbcCoordinator.abortBatch() // since jdbcCoordinator not yet initialized here
)
);
}
private String getTenantId( SessionFactoryImpl factory, SessionCreationOptions options ) {

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@ -24,6 +23,7 @@ import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.AutoFlushEventListener;
@ -72,6 +72,7 @@ import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode;
import jakarta.persistence.PessimisticLockScope;
import static java.util.Collections.unmodifiableMap;
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;
@ -83,19 +84,19 @@ import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
/**
* Internal component.
*
* <p>
* Collects any components that any Session implementation will likely need
* for faster access and reduced allocations.
* Conceptually this acts as an immutable caching intermediary between Session
* and SessionFactory.
* Designed to be immutable, and shared across Session instances.
*
* Assumes to be created infrequently, possibly only once per SessionFactory.
*
* <p>
* Designed to be immutable, shared across Session instances, and created infrequently,
* possibly only once per SessionFactory.
* <p>
* If the Session is requiring to retrieve (or compute) anything from the SessionFactory,
* and this computation would result in the same outcome for any Session created on
* this same SessionFactory, then it belongs in a final field of this class.
*
* <p>
* Finally, consider also limiting the size of each Session: some fields could be good
* candidates to be replaced with access via this object.
*
@ -178,14 +179,14 @@ public final class FastSessionServices {
private final FormatMapper jsonFormatMapper;
private final FormatMapper xmlFormatMapper;
FastSessionServices(SessionFactoryImpl sf) {
Objects.requireNonNull( sf );
final ServiceRegistryImplementor sr = sf.getServiceRegistry();
final JdbcServices jdbcServices = sf.getJdbcServices();
final SessionFactoryOptions sessionFactoryOptions = sf.getSessionFactoryOptions();
FastSessionServices(SessionFactoryImplementor sessionFactory) {
Objects.requireNonNull( sessionFactory );
final ServiceRegistryImplementor serviceRegistry = sessionFactory.getServiceRegistry();
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
final SessionFactoryOptions sessionFactoryOptions = sessionFactory.getSessionFactoryOptions();
// Pre-compute all iterators on Event listeners:
final EventListenerRegistry eventListenerRegistry = sr.getService( EventListenerRegistry.class );
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
this.eventListenerGroup_AUTO_FLUSH = listeners( eventListenerRegistry, EventType.AUTO_FLUSH );
this.eventListenerGroup_CLEAR = listeners( eventListenerRegistry, EventType.CLEAR );
this.eventListenerGroup_DELETE = listeners( eventListenerRegistry, EventType.DELETE );
@ -230,30 +231,34 @@ public final class FastSessionServices {
this.preferredSqlTypeCodeForBoolean = sessionFactoryOptions.getPreferredSqlTypeCodeForBoolean();
this.defaultTimeZoneStorageStrategy = sessionFactoryOptions.getDefaultTimeZoneStorageStrategy();
this.defaultJdbcBatchSize = sessionFactoryOptions.getJdbcBatchSize();
this.requiresMultiTenantConnectionProvider = sf.getSessionFactoryOptions().isMultiTenancyEnabled();
this.requiresMultiTenantConnectionProvider = sessionFactory.getSessionFactoryOptions().isMultiTenancyEnabled();
//Some "hot" services:
this.connectionProvider = requiresMultiTenantConnectionProvider ? null : sr.getService( ConnectionProvider.class );
this.multiTenantConnectionProvider = requiresMultiTenantConnectionProvider ? sr.getService( MultiTenantConnectionProvider.class ) : null;
this.classLoaderService = sr.getService( ClassLoaderService.class );
this.transactionCoordinatorBuilder = sr.getService( TransactionCoordinatorBuilder.class );
this.jdbcServices = sr.getService( JdbcServices.class );
this.entityCopyObserverFactory = sr.getService( EntityCopyObserverFactory.class );
this.connectionProvider = requiresMultiTenantConnectionProvider
? null
: serviceRegistry.getService( ConnectionProvider.class );
this.multiTenantConnectionProvider = requiresMultiTenantConnectionProvider
? serviceRegistry.getService( MultiTenantConnectionProvider.class )
: null;
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
this.transactionCoordinatorBuilder = serviceRegistry.getService( TransactionCoordinatorBuilder.class );
this.jdbcServices = serviceRegistry.getService( JdbcServices.class );
this.entityCopyObserverFactory = serviceRegistry.getService( EntityCopyObserverFactory.class );
this.isJtaTransactionAccessible = isTransactionAccessible( sf, transactionCoordinatorBuilder );
this.isJtaTransactionAccessible = isTransactionAccessible( sessionFactory, transactionCoordinatorBuilder );
this.defaultSessionProperties = initializeDefaultSessionProperties( sf );
this.defaultSessionProperties = initializeDefaultSessionProperties( sessionFactory );
this.defaultCacheStoreMode = determineCacheStoreMode( defaultSessionProperties );
this.defaultCacheRetrieveMode = determineCacheRetrieveMode( defaultSessionProperties );
this.initialSessionCacheMode = CacheModeHelper.interpretCacheMode( defaultCacheStoreMode, defaultCacheRetrieveMode );
this.discardOnClose = sessionFactoryOptions.isReleaseResourcesOnCloseEnabled();
this.defaultJdbcObservers = new ConnectionObserverStatsBridge( sf );
this.defaultJdbcObservers = new ConnectionObserverStatsBridge( sessionFactory );
this.defaultSessionEventListeners = sessionFactoryOptions.getBaselineSessionEventsListenerBuilder();
this.defaultLockOptions = initializeDefaultLockOptions( defaultSessionProperties );
this.initialSessionFlushMode = initializeDefaultFlushMode( defaultSessionProperties );
this.jsonFormatMapper = sessionFactoryOptions.getJsonFormatMapper();
this.xmlFormatMapper = sessionFactoryOptions.getXmlFormatMapper();
this.batchBuilder = sr.getService( BatchBuilder.class );
this.batchBuilder = serviceRegistry.getService( BatchBuilder.class );
}
private static FlushMode initializeDefaultFlushMode(Map<String, Object> defaultSessionProperties) {
@ -271,27 +276,29 @@ public final class FastSessionServices {
return elr.getEventListenerGroup( type );
}
private static boolean isTransactionAccessible(SessionFactoryImpl sf, TransactionCoordinatorBuilder transactionCoordinatorBuilder) {
private static boolean isTransactionAccessible(
SessionFactoryImplementor factory,
TransactionCoordinatorBuilder transactionCoordinatorBuilder) {
// JPA requires that access not be provided to the transaction when using JTA.
// This is overridden when SessionFactoryOptions isJtaTransactionAccessEnabled() is true.
return !( sf.getSessionFactoryOptions().getJpaCompliance().isJpaTransactionComplianceEnabled()
&& transactionCoordinatorBuilder.isJta()
&& !sf.getSessionFactoryOptions().isJtaTransactionAccessEnabled() );
return !factory.getSessionFactoryOptions().getJpaCompliance().isJpaTransactionComplianceEnabled()
|| !transactionCoordinatorBuilder.isJta()
|| factory.getSessionFactoryOptions().isJtaTransactionAccessEnabled();
}
private static Map<String, Object> initializeDefaultSessionProperties(SessionFactoryImpl sf) {
HashMap<String,Object> p = new HashMap<>();
private static Map<String, Object> initializeDefaultSessionProperties(SessionFactoryImplementor factory) {
final HashMap<String,Object> settings = new HashMap<>();
//Static defaults:
p.putIfAbsent( AvailableSettings.FLUSH_MODE, FlushMode.AUTO.name() );
p.putIfAbsent( JPA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() );
p.putIfAbsent( JAKARTA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() );
p.putIfAbsent( JPA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER );
p.putIfAbsent( JAKARTA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER );
p.putIfAbsent( JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE );
p.putIfAbsent( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE );
p.putIfAbsent( JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE );
p.putIfAbsent( JAKARTA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE );
settings.putIfAbsent( AvailableSettings.FLUSH_MODE, FlushMode.AUTO.name() );
settings.putIfAbsent( JPA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() );
settings.putIfAbsent( JAKARTA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() );
settings.putIfAbsent( JPA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER );
settings.putIfAbsent( JAKARTA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER );
settings.putIfAbsent( JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE );
settings.putIfAbsent( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE );
settings.putIfAbsent( JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE );
settings.putIfAbsent( JAKARTA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE );
//Defaults defined by SessionFactory configuration:
final String[] ENTITY_MANAGER_SPECIFIC_PROPERTIES = {
@ -309,41 +316,31 @@ public final class FastSessionServices {
LegacySpecHints.HINT_JAVAEE_CACHE_STORE_MODE,
LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT
};
final Map<String, Object> properties = sf.getProperties();
final Map<String, Object> properties = factory.getProperties();
for ( String key : ENTITY_MANAGER_SPECIFIC_PROPERTIES ) {
if ( properties.containsKey( key ) ) {
p.put( key, properties.get( key ) );
settings.put( key, properties.get( key ) );
}
}
return Collections.unmodifiableMap( p );
return unmodifiableMap( settings );
}
/**
* @param properties the Session properties
* @return either the CacheStoreMode as defined in the Session specific properties, or as defined in the
* properties shared across all sessions (the defaults).
* @return either the CacheStoreMode as defined in the Session specific properties,
* or as defined in the properties shared across all sessions (the defaults).
*/
CacheStoreMode getCacheStoreMode(final Map<String, Object> properties) {
if ( properties == null ) {
return this.defaultCacheStoreMode;
}
else {
return determineCacheStoreMode( properties );
}
return properties == null ? defaultCacheStoreMode : determineCacheStoreMode( properties );
}
/**
* @param properties the Session properties
* @return either the CacheRetrieveMode as defined in the Session specific properties, or as defined in the
* properties shared across all sessions (the defaults).
* @return either the CacheRetrieveMode as defined in the Session specific properties,
* or as defined in the properties shared across all sessions (the defaults).
*/
CacheRetrieveMode getCacheRetrieveMode(Map<String, Object> properties) {
if ( properties == null ) {
return this.defaultCacheRetrieveMode;
}
else {
return determineCacheRetrieveMode( properties );
}
return properties == null ? defaultCacheRetrieveMode : determineCacheRetrieveMode( properties );
}
private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {

View File

@ -9,22 +9,27 @@ package org.hibernate.internal;
import java.sql.Connection;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
/**
* @author Steve Ebersole
*
* @deprecated since {@link JdbcObserver} is deprecated
*/
@Deprecated(since = "5.4", forRemoval = true)
public final class JdbcObserverImpl implements JdbcObserver {
private final ConnectionObserverStatsBridge observer;
private final SessionEventListenerManager eventListenerManager;
private final SharedSessionContractImplementor session;
private final Runnable abortBatch;
public JdbcObserverImpl(SharedSessionContractImplementor session, FastSessionServices fastSessionServices) {
this.session = session;
this.observer = fastSessionServices.getDefaultJdbcObserver();
this.eventListenerManager = session.getEventListenerManager();
public JdbcObserverImpl(
ConnectionObserverStatsBridge observer,
SessionEventListenerManager eventListenerManager,
Runnable abortBatch) {
this.observer = observer;
this.eventListenerManager = eventListenerManager;
this.abortBatch = abortBatch;
}
@Override
@ -78,7 +83,7 @@ public final class JdbcObserverImpl implements JdbcObserver {
@Override
public void jdbcReleaseRegistryResourcesStart() {
session.getJdbcCoordinator().abortBatch();
abortBatch.run();
}
@Override

View File

@ -7,8 +7,10 @@
package org.hibernate.internal;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
@ -22,22 +24,26 @@ public class JdbcSessionContextImpl implements JdbcSessionContext {
private final SessionFactoryImplementor sessionFactory;
private final StatementInspector statementInspector;
private final PhysicalConnectionHandlingMode connectionHandlingMode;
private final JdbcServices jdbcServices;
private final BatchBuilder batchBuilder;
private final transient ServiceRegistry serviceRegistry;
private final transient JdbcObserver jdbcObserver;
public JdbcSessionContextImpl(
SharedSessionContractImplementor session,
SessionFactoryImplementor sessionFactory,
StatementInspector statementInspector,
PhysicalConnectionHandlingMode connectionHandlingMode,
FastSessionServices fastSessionServices) {
this.sessionFactory = session.getFactory();
JdbcServices jdbcServices,
BatchBuilder batchBuilder,
JdbcObserver jdbcObserver) {
this.sessionFactory = sessionFactory;
this.statementInspector = statementInspector;
this.connectionHandlingMode = connectionHandlingMode;
this.serviceRegistry = sessionFactory.getServiceRegistry();
this.jdbcObserver = new JdbcObserverImpl( session, fastSessionServices );
this.jdbcServices = jdbcServices;
this.batchBuilder = batchBuilder;
this.jdbcObserver = jdbcObserver;
if ( this.statementInspector == null ) {
if ( statementInspector == null ) {
throw new IllegalArgumentException( "StatementInspector cannot be null" );
}
}
@ -52,11 +58,31 @@ public class JdbcSessionContextImpl implements JdbcSessionContext {
return settings().isGetGeneratedKeysEnabled();
}
@Override
@Override @Deprecated
public int getFetchSize() {
return settings().getJdbcFetchSize();
}
@Override
public Integer getFetchSizeOrNull() {
return settings().getJdbcFetchSize();
}
@Override
public JpaCompliance getJpaCompliance() {
return settings().getJpaCompliance();
}
@Override
public boolean isPreferUserTransaction() {
return settings().isPreferUserTransaction();
}
@Override
public boolean isJtaTrackByThread() {
return settings().isJtaTrackByThread();
}
@Override
public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() {
return connectionHandlingMode;
@ -72,22 +98,37 @@ public class JdbcSessionContextImpl implements JdbcSessionContext {
return statementInspector;
}
@Override
@Override @Deprecated
public JdbcObserver getObserver() {
return this.jdbcObserver;
return jdbcObserver;
}
@Override
@Override @Deprecated
public SessionFactoryImplementor getSessionFactory() {
return this.sessionFactory;
return sessionFactory;
}
@Override
@Override @Deprecated
public ServiceRegistry getServiceRegistry() {
return this.serviceRegistry;
return sessionFactory.getServiceRegistry();
}
private SessionFactoryOptions settings() {
return this.sessionFactory.getSessionFactoryOptions();
return sessionFactory.getSessionFactoryOptions();
}
@Override
public JdbcServices getJdbcServices() {
return jdbcServices;
}
@Override
public BatchBuilder getBatchBuilder() {
return batchBuilder;
}
@Override
public boolean isActive() {
return !sessionFactory.isClosed();
}
}

View File

@ -22,29 +22,32 @@ public interface LogicalConnection {
* <p>
* That is, has {@link #close} not yet been called?
*
* @return {@code true} if still open ({@link #close} has not been called yet); {@code false} if not open
* ({@link #close} has been called).
* @return {@code true} if still open, since {@link #close} has not yet been called;
* {@code false} if not open, since {@link #close} was called.
*/
boolean isOpen();
/**
* Closes the JdbcSession, making it inactive and forcing release of any held resources.
* Closes the logical connection, making it inactive and forcing release of any held resources.
*
* @return Legacy :( Returns the JDBC {@code Connection} if the user passed in a {@code Connection} originally.
* @return the JDBC {@code Connection} if the user passed in a {@code Connection} originally
*
* @apiNote The return type accommodates legacy functionality for user-supplied connections.
*/
Connection close();
/**
* Is this JdbcSession currently physically connected?
* Is this logical connection currently physically connected?
* <p>
* That is, does it currently hold a physical JDBC {@code Connection}?
* That is, does it currently hold a physical JDBC {@link Connection}?
*
* @return {@code true} if the JdbcSession currently hold a JDBC {@code Connection}; {@code false} if it does not.
* @return {@code true} if currently holding a JDBC {@code Connection};
* {@code false} if not.
*/
boolean isPhysicallyConnected();
/**
* Provides access to the registry of JDBC resources associated with this {@code LogicalConnection}.
* Provides access to the registry of JDBC resources associated with this logical connection.
*
* @return The JDBC resource registry.
*

View File

@ -12,8 +12,6 @@ import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.ConnectionAcquisitionMode;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.ResourceClosedException;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -25,9 +23,15 @@ import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.jboss.logging.Logger;
import static org.hibernate.ConnectionAcquisitionMode.IMMEDIATELY;
import static org.hibernate.ConnectionReleaseMode.AFTER_STATEMENT;
import static org.hibernate.ConnectionReleaseMode.BEFORE_TRANSACTION_COMPLETION;
import static org.hibernate.ConnectionReleaseMode.ON_CLOSE;
import static org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
/**
* Represents a LogicalConnection where we manage obtaining and releasing the Connection as needed.
* This implementation does not claim to be threadsafe and is not designed to be used by multiple
* This implementation does not claim to be thread-safe and is not designed to be used by multiple
* threads, yet we do apply a limited amount of care to be able to void obscure exceptions when
* this class is used in the wrong way.
*
@ -45,7 +49,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
private transient Connection physicalConnection;
private boolean closed;
private boolean providerDisablesAutoCommit;
private final boolean providerDisablesAutoCommit;
public LogicalConnectionManagedImpl(
JdbcConnectionAccess jdbcConnectionAccess,
@ -62,7 +66,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
this.sqlExceptionHelper = jdbcServices.getSqlExceptionHelper();
if ( connectionHandlingMode.getAcquisitionMode() == ConnectionAcquisitionMode.IMMEDIATELY ) {
if ( connectionHandlingMode.getAcquisitionMode() == IMMEDIATELY ) {
acquireConnectionIfNeeded();
}
@ -81,9 +85,9 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
private PhysicalConnectionHandlingMode determineConnectionHandlingMode(
PhysicalConnectionHandlingMode connectionHandlingMode,
JdbcConnectionAccess jdbcConnectionAccess) {
if ( connectionHandlingMode.getReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT
if ( connectionHandlingMode.getReleaseMode() == AFTER_STATEMENT
&& !jdbcConnectionAccess.supportsAggressiveRelease() ) {
return PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
return DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
}
return connectionHandlingMode;
@ -93,8 +97,11 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
JdbcConnectionAccess jdbcConnectionAccess,
JdbcSessionContext jdbcSessionContext,
boolean closed) {
this( jdbcConnectionAccess, jdbcSessionContext, new ResourceRegistryStandardImpl(),
jdbcSessionContext.getSessionFactory().getFastSessionServices().jdbcServices
this(
jdbcConnectionAccess,
jdbcSessionContext,
new ResourceRegistryStandardImpl(),
jdbcSessionContext.getJdbcServices()
);
this.closed = closed;
}
@ -105,7 +112,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
try {
physicalConnection = jdbcConnectionAccess.obtainConnection();
}
catch (SQLException e) {
catch ( SQLException e ) {
throw sqlExceptionHelper.convert( e, "Unable to acquire JDBC Connection" );
}
finally {
@ -140,7 +147,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
public void afterStatement() {
super.afterStatement();
if ( connectionHandlingMode.getReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT ) {
if ( connectionHandlingMode.getReleaseMode() == AFTER_STATEMENT ) {
if ( getResourceRegistry().hasRegisteredResources() ) {
log.debug( "Skipping aggressive release of JDBC Connection after-statement due to held resources" );
}
@ -154,7 +161,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
@Override
public void beforeTransactionCompletion() {
super.beforeTransactionCompletion();
if ( connectionHandlingMode.getReleaseMode() == ConnectionReleaseMode.BEFORE_TRANSACTION_COMPLETION ) {
if ( connectionHandlingMode.getReleaseMode() == BEFORE_TRANSACTION_COMPLETION ) {
log.debug( "Initiating JDBC connection release from beforeTransactionCompletion" );
releaseConnection();
}
@ -164,7 +171,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
public void afterTransaction() {
super.afterTransaction();
if ( connectionHandlingMode.getReleaseMode() != ConnectionReleaseMode.ON_CLOSE ) {
if ( connectionHandlingMode.getReleaseMode() != ON_CLOSE ) {
// NOTE : we check for !ON_CLOSE here (rather than AFTER_TRANSACTION) to also catch:
// - AFTER_STATEMENT cases that were circumvented due to held resources
// - BEFORE_TRANSACTION_COMPLETION cases that were circumvented because a rollback occurred
@ -270,8 +277,8 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
@Override
public void begin() {
initiallyAutoCommit = !doConnectionsFromProviderHaveAutoCommitDisabled() && determineInitialAutoCommitMode(
getConnectionForTransactionManagement() );
initiallyAutoCommit = !doConnectionsFromProviderHaveAutoCommitDisabled()
&& determineInitialAutoCommitMode( getConnectionForTransactionManagement() );
super.begin();
}

View File

@ -9,11 +9,12 @@ package org.hibernate.resource.jdbc.spi;
import java.sql.Connection;
/**
* @deprecated It is no longer possible to plug custom implementations of
* this SPI. It will be removed.
* @deprecated It is no longer possible to plug custom implementations
* of this SPI. It will be removed.
*
* @author Steve Ebersole
*/
@Deprecated
@Deprecated(since = "5.4", forRemoval = true)
public interface JdbcObserver {
void jdbcConnectionAcquisitionStart();
void jdbcConnectionAcquisitionEnd(Connection connection);

View File

@ -6,33 +6,91 @@
*/
package org.hibernate.resource.jdbc.spi;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.service.ServiceRegistry;
/**
* Provides the {@code JdbcSession} with contextual information it needs during its lifecycle.
* Provides the "JDBC session" with contextual information it needs during its lifecycle.
*
* @author Steve Ebersole
*/
public interface JdbcSessionContext {
/**
* @see org.hibernate.cfg.AvailableSettings#USE_SCROLLABLE_RESULTSET
*/
boolean isScrollableResultSetsEnabled();
/**
* @see org.hibernate.cfg.AvailableSettings#USE_GET_GENERATED_KEYS
*/
boolean isGetGeneratedKeysEnabled();
/**
* @see org.hibernate.cfg.AvailableSettings#STATEMENT_FETCH_SIZE
*/
Integer getFetchSizeOrNull();
/**
* @deprecated this is never called, and luckily so, because it's not null-safe
*/
@Deprecated(since = "6.2", forRemoval = true)
int getFetchSize();
/**
* @see org.hibernate.cfg.AvailableSettings#CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT
*/
boolean doesConnectionProviderDisableAutoCommit();
/**
* @see org.hibernate.cfg.AvailableSettings#PREFER_USER_TRANSACTION
*/
boolean isPreferUserTransaction();
/**
* @see org.hibernate.cfg.AvailableSettings#JTA_TRACK_BY_THREAD
*/
boolean isJtaTrackByThread();
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
boolean doesConnectionProviderDisableAutoCommit();
StatementInspector getStatementInspector();
JpaCompliance getJpaCompliance();
/**
* @deprecated since {@link JdbcObserver} is deprecated
*/
@Deprecated(forRemoval = true)
JdbcObserver getObserver();
/**
* Retrieve the session factory for this environment.
*
* @return The session factory
*
* @deprecated exposing this here seems to kinda defeat the purpose of this SPI
*/
@Deprecated(since = "6.2")
SessionFactoryImplementor getSessionFactory();
/**
* Retrieve the service registry.
*
* @deprecated this is no longer called, and unnecessary, since the needed
* services are now available via {@link #getJdbcServices()}
*/
@Deprecated(since = "6.2")
ServiceRegistry getServiceRegistry();
JdbcServices getJdbcServices();
BatchBuilder getBatchBuilder();
/**
* @see org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner#isActive()
*
* @return {@code false} if the session factory was already destroyed
*/
boolean isActive();
}

View File

@ -13,11 +13,13 @@ import java.util.concurrent.Callable;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.transaction.spi.IsolationDelegate;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner;
/**
* @author Andrea Boriero
@ -28,6 +30,17 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
private final JdbcConnectionAccess connectionAccess;
private final SqlExceptionHelper sqlExceptionHelper;
public JdbcIsolationDelegate(TransactionCoordinatorOwner transactionCoordinatorOwner) {
this( transactionCoordinatorOwner.getJdbcSessionOwner() );
}
public JdbcIsolationDelegate(JdbcSessionOwner jdbcSessionOwner) {
this(
jdbcSessionOwner.getJdbcConnectionAccess(),
jdbcSessionOwner.getJdbcSessionContext().getJdbcServices().getSqlExceptionHelper()
);
}
public JdbcIsolationDelegate(JdbcConnectionAccess connectionAccess, SqlExceptionHelper sqlExceptionHelper) {
this.connectionAccess = connectionAccess;
this.sqlExceptionHelper = sqlExceptionHelper;
@ -45,7 +58,7 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
public <T> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) throws HibernateException {
boolean wasAutoCommit = false;
try {
Connection connection = jdbcConnectionAccess().obtainConnection();
final Connection connection = jdbcConnectionAccess().obtainConnection();
try {
if ( transacted ) {
if ( connection.getAutoCommit() ) {
@ -62,14 +75,14 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
return result;
}
catch (Exception e) {
catch ( Exception e ) {
try {
if ( transacted && !connection.isClosed() ) {
connection.rollback();
}
}
catch (Exception ignore) {
LOG.unableToRollbackConnection( ignore );
catch ( Exception exception ) {
LOG.unableToRollbackConnection( exception );
}
if ( e instanceof HibernateException ) {
@ -87,19 +100,19 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
try {
connection.setAutoCommit( true );
}
catch (Exception ignore) {
catch ( Exception ignore ) {
LOG.trace( "was unable to reset connection back to auto-commit" );
}
}
try {
jdbcConnectionAccess().releaseConnection( connection );
}
catch (Exception ignore) {
catch ( Exception ignore ) {
LOG.unableToReleaseIsolatedConnection( ignore );
}
}
}
catch (SQLException sqle) {
catch ( SQLException sqle ) {
throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
}
}
@ -110,11 +123,11 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
try {
return callable.call();
}
catch (HibernateException e) {
catch ( HibernateException e ) {
throw e;
}
catch (Exception e) {
throw new HibernateException(e);
catch ( Exception e ) {
throw new HibernateException( e );
}
}
}

View File

@ -15,6 +15,8 @@ import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner;
import org.hibernate.tool.schema.internal.exec.JdbcContext;
import static org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
/**
* Concrete builder for resource-local {@link TransactionCoordinator} instances.
*
@ -50,7 +52,7 @@ public class JdbcResourceLocalTransactionCoordinatorBuilderImpl implements Trans
@Override
public PhysicalConnectionHandlingMode getDefaultConnectionHandlingMode() {
return PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
return DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
}
@Override

View File

@ -7,7 +7,6 @@
package org.hibernate.resource.transaction.backend.jdbc.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jakarta.persistence.RollbackException;
@ -16,7 +15,6 @@ import jakarta.transaction.Status;
import org.hibernate.resource.transaction.spi.IsolationDelegate;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransaction;
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransactionAccess;
import org.hibernate.resource.transaction.internal.SynchronizationRegistryStandardImpl;
@ -27,6 +25,7 @@ import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner;
import org.hibernate.resource.transaction.spi.TransactionObserver;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import static java.util.Collections.emptyList;
import static org.hibernate.internal.CoreLogging.messageLogger;
/**
@ -66,12 +65,7 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
this.transactionCoordinatorBuilder = transactionCoordinatorBuilder;
this.jdbcResourceTransactionAccess = jdbcResourceTransactionAccess;
this.transactionCoordinatorOwner = owner;
this.jpaCompliance = owner.getJdbcSessionOwner()
.getJdbcSessionContext()
.getSessionFactory()
.getSessionFactoryOptions()
.getJpaCompliance();
this.jpaCompliance = owner.getJdbcSessionOwner().getJdbcSessionContext().getJpaCompliance();
}
/**
@ -81,12 +75,7 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
* @return TransactionObserver
*/
private Iterable<TransactionObserver> observers() {
if ( observers == null || observers.isEmpty() ) {
return Collections.emptyList();
}
else {
return new ArrayList<>( observers );
}
return observers == null || observers.isEmpty() ? emptyList() : new ArrayList<>( observers );
}
@Override
@ -95,7 +84,8 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
// coordinator. We lazily build it as we invalidate each delegate after each transaction (a delegate is
// valid for just one transaction)
if ( physicalTransactionDelegate == null ) {
physicalTransactionDelegate = new TransactionDriverControlImpl( jdbcResourceTransactionAccess.getResourceLocalTransaction() );
physicalTransactionDelegate =
new TransactionDriverControlImpl( jdbcResourceTransactionAccess.getResourceLocalTransaction() );
}
return physicalTransactionDelegate;
}
@ -108,7 +98,8 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
@Override
public boolean isJoined() {
return physicalTransactionDelegate != null && getTransactionDriverControl().isActive( true );
return physicalTransactionDelegate != null
&& getTransactionDriverControl().isActive( true );
}
@Override
@ -133,17 +124,12 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
@Override
public IsolationDelegate createIsolationDelegate() {
final JdbcSessionOwner jdbcSessionOwner = transactionCoordinatorOwner.getJdbcSessionOwner();
return new JdbcIsolationDelegate(
jdbcSessionOwner.getJdbcConnectionAccess(),
jdbcSessionOwner.getJdbcSessionContext().getSessionFactory().getFastSessionServices().jdbcServices.getSqlExceptionHelper()
);
return new JdbcIsolationDelegate( transactionCoordinatorOwner );
}
@Override
public TransactionCoordinatorBuilder getTransactionCoordinatorBuilder() {
return this.transactionCoordinatorBuilder;
return transactionCoordinatorBuilder;
}
@Override
@ -153,14 +139,14 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
@Override
public int getTimeOut() {
return this.timeOut;
return timeOut;
}
// PhysicalTransactionDelegate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private void afterBeginCallback() {
if(this.timeOut > 0) {
transactionCoordinatorOwner.setTransactionTimeOut( this.timeOut );
if ( timeOut > 0 ) {
transactionCoordinatorOwner.setTransactionTimeOut( timeOut );
}

View File

@ -17,12 +17,14 @@ import java.util.concurrent.Callable;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.transaction.spi.IsolationDelegate;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner;
/**
* An isolation delegate for JTA environments.
@ -36,6 +38,18 @@ public class JtaIsolationDelegate implements IsolationDelegate {
private final SqlExceptionHelper sqlExceptionHelper;
private final TransactionManager transactionManager;
public JtaIsolationDelegate(TransactionCoordinatorOwner transactionCoordinatorOwner, TransactionManager transactionManager) {
this( transactionCoordinatorOwner.getJdbcSessionOwner(), transactionManager );
}
public JtaIsolationDelegate(JdbcSessionOwner jdbcSessionOwner, TransactionManager transactionManager) {
this(
jdbcSessionOwner.getJdbcConnectionAccess(),
jdbcSessionOwner.getJdbcSessionContext().getJdbcServices().getSqlExceptionHelper(),
transactionManager
);
}
public JtaIsolationDelegate(
JdbcConnectionAccess connectionAccess,
SqlExceptionHelper sqlExceptionHelper,
@ -46,74 +60,53 @@ public class JtaIsolationDelegate implements IsolationDelegate {
}
protected JdbcConnectionAccess jdbcConnectionAccess() {
return this.connectionAccess;
return connectionAccess;
}
protected SqlExceptionHelper sqlExceptionHelper() {
return this.sqlExceptionHelper;
return sqlExceptionHelper;
}
@Override
public <T> T delegateWork(final WorkExecutorVisitable<T> work, final boolean transacted) throws HibernateException {
return doInSuspendedTransaction(new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
HibernateCallable<T> workCallable = new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
return doTheWork(work);
}
};
if ( transacted ) {
return doInNewTransaction( workCallable, transactionManager );
}
else {
return workCallable.call();
}
}
});
return doInSuspendedTransaction(
() -> transacted
? doInNewTransaction( () -> doTheWork( work ), transactionManager )
: doTheWork( work )
);
}
@Override
public <T> T delegateCallable(final Callable<T> callable, final boolean transacted) throws HibernateException {
return doInSuspendedTransaction(new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
HibernateCallable<T> workCallable = new HibernateCallable<T>() {
@Override
public T call() throws HibernateException {
try {
return callable.call();
}
catch (HibernateException e) {
throw e;
}
catch (Exception e) {
throw new HibernateException(e);
}
}
};
if ( transacted ) {
return doInNewTransaction( workCallable, transactionManager );
}
else {
return workCallable.call();
}
}
});
return doInSuspendedTransaction(
() -> transacted
? doInNewTransaction( () -> call( callable ), transactionManager )
: call( callable ));
}
private static <T> T call(final Callable<T> callable) {
try {
return callable.call();
}
catch ( HibernateException e ) {
throw e;
}
catch ( Exception e ) {
throw new HibernateException( e );
}
}
private <T> T doInSuspendedTransaction(HibernateCallable<T> callable) {
Throwable originalException = null;
try {
// First we suspend any current JTA transaction
Transaction surroundingTransaction = transactionManager.suspend();
final Transaction surroundingTransaction = transactionManager.suspend();
LOG.debugf( "Surrounding JTA transaction suspended [%s]", surroundingTransaction );
try {
return callable.call();
}
catch (Throwable t1) {
catch ( Throwable t1 ) {
originalException = t1;
}
finally {
@ -121,7 +114,7 @@ public class JtaIsolationDelegate implements IsolationDelegate {
transactionManager.resume( surroundingTransaction );
LOG.debugf( "Surrounding JTA transaction resumed [%s]", surroundingTransaction );
}
catch (Throwable t2) {
catch ( Throwable t2 ) {
// if the actually work had an error use that, otherwise error based on t
if ( originalException == null ) {
originalException = new HibernateException( "Unable to resume previously suspended transaction", t2 );
@ -132,7 +125,7 @@ public class JtaIsolationDelegate implements IsolationDelegate {
}
}
}
catch (SystemException e) {
catch ( SystemException e ) {
originalException = new HibernateException( "Unable to suspend current JTA transaction", e );
}
@ -144,27 +137,23 @@ public class JtaIsolationDelegate implements IsolationDelegate {
try {
// start the new isolated transaction
transactionManager.begin();
try {
T result = callable.call();
// if everything went ok, commit the isolated transaction
transactionManager.commit();
return result;
}
catch (Exception e) {
catch ( Exception e ) {
try {
transactionManager.rollback();
}
catch (Exception ignore) {
LOG.unableToRollbackIsolatedTransaction( e, ignore );
catch ( Exception exception ) {
LOG.unableToRollbackIsolatedTransaction( e, exception );
}
throw new HibernateException( "Could not apply work", e );
}
}
catch (SystemException e) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
catch (NotSupportedException e) {
catch ( SystemException | NotSupportedException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
}
@ -177,10 +166,10 @@ public class JtaIsolationDelegate implements IsolationDelegate {
// do the actual work
return work.accept( new WorkExecutor<>(), connection );
}
catch (HibernateException e) {
catch ( HibernateException e ) {
throw e;
}
catch (Exception e) {
catch ( Exception e ) {
throw new HibernateException( "Unable to perform isolated work", e );
}
finally {
@ -188,8 +177,8 @@ public class JtaIsolationDelegate implements IsolationDelegate {
// no matter what, release the connection (handle)
jdbcConnectionAccess().releaseConnection( connection );
}
catch (Throwable ignore) {
LOG.unableToReleaseIsolatedConnection( ignore );
catch ( Throwable throwable ) {
LOG.unableToReleaseIsolatedConnection( throwable );
}
}
}

View File

@ -16,6 +16,8 @@ import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.internal.exec.JdbcContext;
import static org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT;
/**
* Concrete builder for JTA-based TransactionCoordinator instances.
*
@ -44,8 +46,8 @@ public class JtaTransactionCoordinatorBuilderImpl implements TransactionCoordina
@Override
public PhysicalConnectionHandlingMode getDefaultConnectionHandlingMode() {
// todo : I want to change this to PhysicalConnectionHandlingMode#IMMEDIATE_ACQUISITION_AND_HOLD
return PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT;
// todo : I want to change this to IMMEDIATE_ACQUISITION_AND_HOLD
return DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT;
}
@Override
@ -55,7 +57,7 @@ public class JtaTransactionCoordinatorBuilderImpl implements TransactionCoordina
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.jtaPlatform = serviceRegistry.getService( JtaPlatform.class );
jtaPlatform = serviceRegistry.getService( JtaPlatform.class );
}
}

View File

@ -7,19 +7,15 @@
package org.hibernate.resource.transaction.backend.jta.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jakarta.transaction.Status;
import jakarta.transaction.TransactionManager;
import jakarta.transaction.UserTransaction;
import org.hibernate.HibernateException;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.resource.transaction.spi.IsolationDelegate;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.transaction.TransactionRequiredForJoinException;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinator;
@ -36,7 +32,11 @@ import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.jboss.logging.Logger;
import static java.util.Collections.addAll;
import static java.util.Collections.emptyList;
import static org.hibernate.internal.CoreLogging.logger;
import static org.hibernate.resource.transaction.spi.TransactionStatus.ACTIVE;
import static org.hibernate.resource.transaction.spi.TransactionStatus.NOT_ACTIVE;
/**
* An implementation of TransactionCoordinator based on managing a transaction through the JTA API (either TM or UT)
@ -83,9 +83,8 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
this.jtaPlatform = jtaPlatform;
final SessionFactoryOptions sessionFactoryOptions = jdbcSessionContext.getSessionFactory().getSessionFactoryOptions();
this.preferUserTransactions = sessionFactoryOptions.isPreferUserTransaction();
this.performJtaThreadTracking = sessionFactoryOptions.isJtaTrackByThread();
this.preferUserTransactions = jdbcSessionContext.isPreferUserTransaction();
this.performJtaThreadTracking = jdbcSessionContext.isJtaTrackByThread();
synchronizationRegistered = false;
@ -109,7 +108,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
if ( observers != null ) {
this.observers = new ArrayList<>( observers.length );
Collections.addAll( this.observers, observers );
addAll( this.observers, observers );
}
synchronizationRegistered = false;
@ -125,12 +124,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
* @return TransactionObserver
*/
private Iterable<TransactionObserver> observers() {
if ( this.observers == null ) {
return Collections.EMPTY_LIST;
}
else {
return new ArrayList<>( this.observers );
}
return observers == null ? emptyList() : new ArrayList<>( observers );
}
public SynchronizationCallbackCoordinator getSynchronizationCallbackCoordinator() {
@ -186,7 +180,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
return;
}
if ( getTransactionDriverControl().getStatus() != TransactionStatus.ACTIVE ) {
if ( getTransactionDriverControl().getStatus() != ACTIVE ) {
throw new TransactionRequiredForJoinException(
"Explicitly joining a JTA transaction requires a JTA transaction be currently active"
);
@ -217,11 +211,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
@Override
public JpaCompliance getJpaCompliance() {
return transactionCoordinatorOwner.getJdbcSessionOwner()
.getJdbcSessionContext()
.getSessionFactory()
.getSessionFactoryOptions()
.getJpaCompliance();
return transactionCoordinatorOwner.getJdbcSessionOwner().getJdbcSessionContext().getJpaCompliance();
}
@Override
@ -271,8 +261,8 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
return new JtaTransactionAdapterUserTransactionImpl( userTransaction );
}
}
catch (Exception ignore) {
log.debugf( "JtaPlatform#retrieveUserTransaction threw an exception [%s]", ignore.getMessage() );
catch ( Exception exception ) {
log.debugf( "JtaPlatform#retrieveUserTransaction threw an exception [%s]", exception.getMessage() );
}
return null;
@ -288,8 +278,8 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
return new JtaTransactionAdapterTransactionManagerImpl( transactionManager );
}
}
catch (Exception ignore) {
log.debugf( "JtaPlatform#retrieveTransactionManager threw an exception [%s]", ignore.getMessage() );
catch ( Exception exception ) {
log.debugf( "JtaPlatform#retrieveTransactionManager threw an exception [%s]", exception.getMessage() );
}
return null;
@ -306,25 +296,17 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
}
public boolean isJtaTransactionCurrentlyActive() {
return getTransactionDriverControl().getStatus() == TransactionStatus.ACTIVE;
return getTransactionDriverControl().getStatus() == ACTIVE;
}
@Override
public IsolationDelegate createIsolationDelegate() {
final JdbcSessionOwner jdbcSessionOwner = transactionCoordinatorOwner.getJdbcSessionOwner();
return new JtaIsolationDelegate(
jdbcSessionOwner.getJdbcConnectionAccess(),
jdbcSessionOwner.getJdbcSessionContext()
.getSessionFactory()
.getFastSessionServices().jdbcServices.getSqlExceptionHelper(),
jtaPlatform.retrieveTransactionManager()
);
return new JtaIsolationDelegate( transactionCoordinatorOwner, jtaPlatform.retrieveTransactionManager() );
}
@Override
public TransactionCoordinatorBuilder getTransactionCoordinatorBuilder() {
return this.transactionCoordinatorBuilder;
return transactionCoordinatorBuilder;
}
@Override
@ -335,7 +317,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
@Override
public int getTimeOut() {
return this.timeOut;
return timeOut;
}
@Override
@ -353,14 +335,10 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
try {
transactionCoordinatorOwner.beforeTransactionCompletion();
}
catch (HibernateException e) {
catch ( Exception e ) {
physicalTransactionDelegate.markRollbackOnly();
throw e;
}
catch (RuntimeException re) {
physicalTransactionDelegate.markRollbackOnly();
throw re;
}
finally {
synchronizationRegistry.notifySynchronizationsBeforeTransactionCompletion();
for ( TransactionObserver observer : observers() ) {
@ -390,8 +368,8 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
}
public void addObserver(TransactionObserver observer) {
if ( this.observers == null ) {
this.observers = new ArrayList<>( 3 ); //These lists are typically very small.
if ( observers == null ) {
observers = new ArrayList<>( 3 ); //These lists are typically very small.
}
observers.add( observer );
}
@ -460,7 +438,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
@Override
public void markRollbackOnly() {
if ( jtaTransactionAdapter.getStatus() != TransactionStatus.NOT_ACTIVE ) {
if ( jtaTransactionAdapter.getStatus() != NOT_ACTIVE ) {
jtaTransactionAdapter.markRollbackOnly();
}
}

View File

@ -8,6 +8,9 @@ package org.hibernate.resource.transaction.spi;
import org.hibernate.jpa.spi.JpaCompliance;
import static org.hibernate.resource.transaction.spi.TransactionStatus.ACTIVE;
import static org.hibernate.resource.transaction.spi.TransactionStatus.MARKED_ROLLBACK;
/**
* Models the coordination of all transaction related flows.
*
@ -52,14 +55,14 @@ public interface TransactionCoordinator {
boolean isJoined();
/**
* Used by owner of the JdbcSession as a means to indicate that implicit joining should be done if needed.
* Used by owner of the "JDBC session" as a means to indicate that implicit joining should be done if needed.
*/
void pulse();
/**
* Is this transaction still active?
* <p>
* Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a
* Answers on a best-effort basis. For example, in the case of JDBC based transactions we cannot know that a
* transaction is active when it is initiated directly through the JDBC {@link java.sql.Connection}, only when
* it is initiated from here.
*
@ -101,7 +104,8 @@ public interface TransactionCoordinator {
}
default boolean isTransactionActive(boolean isMarkedRollbackConsideredActive) {
return isJoined() && getTransactionDriverControl().isActive( isMarkedRollbackConsideredActive );
return isJoined()
&& getTransactionDriverControl().isActive( isMarkedRollbackConsideredActive );
}
default void invalidate(){}
@ -134,8 +138,8 @@ public interface TransactionCoordinator {
default boolean isActive(boolean isMarkedRollbackConsideredActive) {
final TransactionStatus status = getStatus();
return TransactionStatus.ACTIVE == status
|| ( isMarkedRollbackConsideredActive && TransactionStatus.MARKED_ROLLBACK == status );
return status == ACTIVE
|| isMarkedRollbackConsideredActive && status == MARKED_ROLLBACK;
}
// todo : org.hibernate.Transaction will need access to register local Synchronizations.

View File

@ -127,8 +127,7 @@ public abstract class AbstractBatchingTest {
// a legacy implementation does not call abortBatch().
final JdbcServices jdbcServices = jdbcCoordinator.getJdbcSessionOwner()
.getJdbcSessionContext()
.getServiceRegistry()
.getService( JdbcServices.class );
.getJdbcServices();
throw jdbcServices.getSqlExceptionHelper().convert(
new SQLException( "fake SQLException" ),
"could not perform addBatch",