HHH-11542 - Allow the auto-commit resolution to be configurable for RESOURCE_LOCAL transactions
This commit is contained in:
parent
ca103dcb28
commit
db528238d8
|
@ -53,14 +53,34 @@ Note that for backwards compatibility, if a https://docs.jboss.org/hibernate/orm
|
|||
|`hibernate.connection.password` or `javax.persistence.jdbc.password` | | Names the JDBC connection password.
|
||||
|`hibernate.connection.isolation` | `REPEATABLE_READ` or
|
||||
`Connection.TRANSACTION_REPEATABLE_READ` | Names the JDBC connection transaction isolation level.
|
||||
|`hibernate.connection.autocommit` | `true` or `false` (default value) | Names the JDBC connection autocommit mode.
|
||||
|`hibernate.connection.skip_autocommit_check` | `true` or `false` (default value) |
|
||||
|`hibernate.connection.autocommit` | `true` or `false` (default value) | Names the initial autocommit mode for JDBC Connections returned from a connection pool created in certain ConnectionProvider impl. See discussion of `hibernate.transaction.skip_setautocommit` as well.
|
||||
|
||||
When using an external non-JTA `DataSource`, it might be that the underlying `DataSource` already disables the autocommit mode,
|
||||
so there is no need to check this `Connection` attribute upon starting a RESOURCE_LOCAL transaction.
|
||||
|`hibernate.connection.provider_disables_autocommit` | `true` or `false` (default value) |
|
||||
|
||||
By setting it to `true`, the `Connection` acquisition can be delayed until the first SQL statement is needed to be executed.
|
||||
The connection acquisition delay allows you to reduce the database connection lease time, therefore allowing you to increase the transaction throughput.
|
||||
Indicates a promise by the user that Connections that Hibernate obtains from the configured ConnectionProvider
|
||||
have auto-commit disabled when they are obtained from that provider, whether that provider is backed by
|
||||
a DataSource or some other Connection pooling mechanism. Generally this occurs when:
|
||||
|
||||
* Hibernate is configured to get Connections from an underlying DataSource, and that DataSource is already configured to disable auto-commit on its managed Connections
|
||||
* Hibernate is configured to get Connections from a non-DataSource connection pool and that connection pool is already configured to disable auto-commit. For the
|
||||
Hibernate provided impls this will depend on the value of {@link #AUTOCOMMIT} setting.
|
||||
|
||||
Hibernate uses this assurance as an opportunity to opt-out of certain operations that may have a performance
|
||||
impact (although this impact is general negligible). Specifically, when a transaction is started via the
|
||||
Hibernate or JPA transaction APIs Hibernate will generally immediately acquire a Connection from the
|
||||
provider and:
|
||||
|
||||
* check whether the Connection is initially in auto-commit mode via a call to `Connection#getAutocommit` to know how to clean up the Connection when released.
|
||||
* start a JDBC transaction by calling `Connection#setAutocommit(false)`
|
||||
|
||||
We can skip both of those steps if we know that the ConnectionProvider will always return Connections with auto-commit disabled.
|
||||
That is the purpose of this setting. By setting it to `true`, the `Connection` acquisition can be delayed until the first
|
||||
SQL statement is needed to be executed. The connection acquisition delay allows you to reduce the database connection lease
|
||||
time, therefore allowing you to increase the transaction throughput.
|
||||
|
||||
Please note however that it is inappropriate to set this value to `true` when the Connections Hibernate gets
|
||||
from the provider do not in fact have auto-commit disabled - doing so will lead to Hibernate executing SQL operations
|
||||
outside of any JDBC/SQL transaction.
|
||||
|
||||
|`hibernate.connection.datasource` | |
|
||||
|
||||
|
@ -529,6 +549,7 @@ The ability to handle this situation requires checking the Thread ID every time
|
|||
|
||||
|`hibernate.transaction.factory_class` | | This is a legacy setting that's been deprecated and you should use the `hibernate.transaction.jta.platform` instead.
|
||||
|
||||
|
||||
|===================================================================================================================================================================================================================================
|
||||
|
||||
[[configurations-multi-tenancy]]
|
||||
|
|
|
@ -663,6 +663,11 @@ public interface SessionFactoryBuilder {
|
|||
@Deprecated
|
||||
SessionFactoryBuilder applyConnectionReleaseMode(ConnectionReleaseMode connectionReleaseMode);
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT
|
||||
*/
|
||||
SessionFactoryBuilder applyConnectionProviderDisablesAutoCommit(boolean providerDisablesAutoCommit);
|
||||
|
||||
/**
|
||||
* Should Hibernate apply comments to SQL it generates?
|
||||
*
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
|||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.engine.config.internal.ConfigurationServiceImpl;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
|
@ -406,6 +407,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder applyConnectionProviderDisablesAutoCommit(boolean providerDisablesAutoCommit) {
|
||||
this.options.connectionProviderDisablesAutoCommit = providerDisablesAutoCommit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder applySqlComments(boolean enabled) {
|
||||
this.options.commentsEnabled = enabled;
|
||||
|
@ -553,6 +560,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
private boolean scrollableResultSetsEnabled;
|
||||
private boolean commentsEnabled;
|
||||
private PhysicalConnectionHandlingMode connectionHandlingMode;
|
||||
private boolean connectionProviderDisablesAutoCommit;
|
||||
private boolean wrapResultSetsEnabled;
|
||||
private TimeZone jdbcTimeZone;
|
||||
private boolean queryParametersValidationEnabled;
|
||||
|
@ -725,6 +733,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
this.jdbcFetchSize = ConfigurationHelper.getInteger( STATEMENT_FETCH_SIZE, configurationSettings );
|
||||
|
||||
this.connectionHandlingMode = interpretConnectionHandlingMode( configurationSettings, serviceRegistry );
|
||||
this.connectionProviderDisablesAutoCommit = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT,
|
||||
configurationSettings,
|
||||
false
|
||||
);
|
||||
|
||||
this.commentsEnabled = ConfigurationHelper.getBoolean( USE_SQL_COMMENTS, configurationSettings );
|
||||
|
||||
|
@ -1155,6 +1168,10 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return connectionHandlingMode;
|
||||
}
|
||||
|
||||
public boolean connectionProviderDisablesAutoCommit() {
|
||||
return connectionProviderDisablesAutoCommit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionReleaseMode getConnectionReleaseMode() {
|
||||
return getPhysicalConnectionHandlingMode().getReleaseMode();
|
||||
|
@ -1478,6 +1495,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return options.getPhysicalConnectionHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectionProviderDisablesAutoCommit() {
|
||||
return options.connectionProviderDisablesAutoCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionReleaseMode getConnectionReleaseMode() {
|
||||
return getPhysicalConnectionHandlingMode().getReleaseMode();
|
||||
|
|
|
@ -121,6 +121,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
private final boolean scrollableResultSetsEnabled;
|
||||
private final boolean commentsEnabled;
|
||||
private final PhysicalConnectionHandlingMode physicalConnectionHandlingMode;
|
||||
private final boolean connectionProviderDisablesAutoCommit;
|
||||
private final boolean wrapResultSetsEnabled;
|
||||
private final TimeZone jdbcTimeZone;
|
||||
|
||||
|
@ -192,6 +193,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
|
||||
this.schemaAutoTooling = state.getSchemaAutoTooling();
|
||||
this.physicalConnectionHandlingMode = state.getPhysicalConnectionHandlingMode();
|
||||
this.connectionProviderDisablesAutoCommit = state.connectionProviderDisablesAutoCommit();
|
||||
this.getGeneratedKeysEnabled = state.isGetGeneratedKeysEnabled();
|
||||
this.jdbcBatchSize = state.getJdbcBatchSize();
|
||||
this.jdbcBatchVersionedData = state.isJdbcBatchVersionedData();
|
||||
|
@ -490,6 +492,11 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
return physicalConnectionHandlingMode.getReleaseMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesConnectionProviderDisableAutoCommit() {
|
||||
return connectionProviderDisablesAutoCommit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommentsEnabled() {
|
||||
return commentsEnabled;
|
||||
|
|
|
@ -155,6 +155,8 @@ public interface SessionFactoryOptionsState {
|
|||
|
||||
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
||||
|
||||
boolean connectionProviderDisablesAutoCommit();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getPhysicalConnectionHandlingMode()} instead
|
||||
*/
|
||||
|
|
|
@ -348,6 +348,12 @@ public abstract class AbstractDelegatingSessionFactoryBuilder<T extends Abstract
|
|||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder applyConnectionProviderDisablesAutoCommit(boolean providerDisablesAutoCommit) {
|
||||
delegate.applyConnectionProviderDisablesAutoCommit( providerDisablesAutoCommit );
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T applySqlComments(boolean enabled) {
|
||||
delegate.applySqlComments( enabled );
|
||||
|
|
|
@ -319,6 +319,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
return delegate.getPhysicalConnectionHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesConnectionProviderDisableAutoCommit() {
|
||||
return delegate.doesConnectionProviderDisableAutoCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public ConnectionReleaseMode getConnectionReleaseMode() {
|
||||
|
|
|
@ -181,6 +181,8 @@ public interface SessionFactoryOptions {
|
|||
|
||||
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
||||
|
||||
boolean doesConnectionProviderDisableAutoCommit();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getPhysicalConnectionHandlingMode()} instead
|
||||
*/
|
||||
|
|
|
@ -324,9 +324,12 @@ public interface AvailableSettings {
|
|||
String ISOLATION ="hibernate.connection.isolation";
|
||||
|
||||
/**
|
||||
* Names the {@literal JDBC} autocommit mode
|
||||
* Controls the autocommit mode of {@literal JDBC} Connections obtained
|
||||
* from a non-DataSource ConnectionProvider - assuming the ConnectionProvider
|
||||
* impl properly leverages this setting (the provided Hibernate impls all
|
||||
* do).
|
||||
*/
|
||||
String AUTOCOMMIT ="hibernate.connection.autocommit";
|
||||
String AUTOCOMMIT = "hibernate.connection.autocommit";
|
||||
|
||||
/**
|
||||
* Maximum number of inactive connections for the built-in Hibernate connection pool.
|
||||
|
@ -343,12 +346,16 @@ public interface AvailableSettings {
|
|||
String DATASOURCE ="hibernate.connection.datasource";
|
||||
|
||||
/**
|
||||
* Instructs Hibernate to skip the autocommit check for local transactions since
|
||||
* the underlying {@link javax.sql.DataSource} has already disabled autocommit.
|
||||
* Allows a user to tell Hibernate that the Connections we obtain from the configured
|
||||
* ConnectionProvider will already have auto-commit disabled when we acquire them from
|
||||
* the provider. When we get connections already in auto-commit, this allows us to circumvent
|
||||
* some operations in the interest of performance.
|
||||
* <p/>
|
||||
* Default value is {@code false} - do not skip, aka call setAutocommit
|
||||
*
|
||||
* @since 5.2.10
|
||||
*/
|
||||
String SKIP_AUTOCOMMIT_CHECK ="hibernate.connection.skip_autocommit_check";
|
||||
String CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT= "hibernate.connection.provider_disables_autocommit";
|
||||
|
||||
/**
|
||||
* Names a prefix used to define arbitrary JDBC connection properties. These properties are passed along to
|
||||
|
|
|
@ -60,6 +60,11 @@ public class JdbcSessionContextImpl implements JdbcSessionContext {
|
|||
return connectionHandlingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesConnectionProviderDisableAutoCommit() {
|
||||
return settings().doesConnectionProviderDisableAutoCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionReleaseMode getConnectionReleaseMode() {
|
||||
return connectionHandlingMode.getReleaseMode();
|
||||
|
|
|
@ -62,7 +62,7 @@ public abstract class AbstractLogicalConnectionImplementor implements LogicalCon
|
|||
@Override
|
||||
public void begin() {
|
||||
try {
|
||||
if ( !isSkipAutoCommitCheck() ) {
|
||||
if ( !doConnectionsFromProviderHaveAutoCommitDisabled() ) {
|
||||
log.trace( "Preparing to begin transaction via JDBC Connection.setAutoCommit(false)" );
|
||||
getConnectionForTransactionManagement().setAutoCommit( false );
|
||||
log.trace( "Transaction begun via JDBC Connection.setAutoCommit(false)" );
|
||||
|
@ -139,7 +139,7 @@ public abstract class AbstractLogicalConnectionImplementor implements LogicalCon
|
|||
return status;
|
||||
}
|
||||
|
||||
protected boolean isSkipAutoCommitCheck() {
|
||||
protected boolean doConnectionsFromProviderHaveAutoCommitDisabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
|
|||
private transient Connection physicalConnection;
|
||||
private boolean closed;
|
||||
|
||||
private boolean skipAutoCommitCheck;
|
||||
private boolean providerDisablesAutoCommit;
|
||||
|
||||
public LogicalConnectionManagedImpl(
|
||||
JdbcConnectionAccess jdbcConnectionAccess,
|
||||
|
@ -76,14 +76,16 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
|
|||
acquireConnectionIfNeeded();
|
||||
}
|
||||
|
||||
ConfigurationService configurationService = jdbcSessionContext.getServiceRegistry()
|
||||
.getService( ConfigurationService.class );
|
||||
|
||||
this.skipAutoCommitCheck = configurationService.getSetting(
|
||||
AvailableSettings.SKIP_AUTOCOMMIT_CHECK,
|
||||
StandardConverters.BOOLEAN,
|
||||
false
|
||||
);
|
||||
this.providerDisablesAutoCommit = jdbcSessionContext.doesConnectionProviderDisableAutoCommit();
|
||||
if ( providerDisablesAutoCommit ) {
|
||||
log.debug(
|
||||
"`hibernate.connection.provider_disables_autocommit` was enabled. This setting should only be " +
|
||||
"enabled when you are certain that the Connections given to Hibernate by the " +
|
||||
"ConnectionProvider have auto-commit disabled. Enabling this setting when the " +
|
||||
"Connections do not have auto-commit disabled will lead to Hibernate executing " +
|
||||
"SQL operations outside of any JDBC/SQL transaction."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private PhysicalConnectionHandlingMode determineConnectionHandlingMode(
|
||||
|
@ -265,7 +267,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
|
|||
|
||||
@Override
|
||||
public void begin() {
|
||||
initiallyAutoCommit = !isSkipAutoCommitCheck() && determineInitialAutoCommitMode(
|
||||
initiallyAutoCommit = !doConnectionsFromProviderHaveAutoCommitDisabled() && determineInitialAutoCommitMode(
|
||||
getConnectionForTransactionManagement() );
|
||||
super.begin();
|
||||
}
|
||||
|
@ -279,7 +281,7 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSkipAutoCommitCheck() {
|
||||
return skipAutoCommitCheck;
|
||||
protected boolean doConnectionsFromProviderHaveAutoCommitDisabled() {
|
||||
return providerDisablesAutoCommit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ public interface JdbcSessionContext {
|
|||
|
||||
PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode();
|
||||
|
||||
boolean doesConnectionProviderDisableAutoCommit();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getPhysicalConnectionHandlingMode} instead
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.lang.reflect.Field;
|
|||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
|
@ -12,7 +11,6 @@ import org.hibernate.engine.jdbc.batch.spi.Batch;
|
|||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcObserver;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
|
||||
|
@ -70,7 +68,7 @@ public class JdbcCoordinatorTest {
|
|||
ConfigurationService configurationService = Mockito.mock( ConfigurationService.class );
|
||||
when( serviceRegistry.getService( eq( ConfigurationService.class ) ) ).thenReturn(
|
||||
configurationService );
|
||||
when( configurationService.getSetting(eq( AvailableSettings.SKIP_AUTOCOMMIT_CHECK ), same( StandardConverters.BOOLEAN), eq( false )) )
|
||||
when( configurationService.getSetting( eq( AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT ), same( StandardConverters.BOOLEAN), eq( false )) )
|
||||
.thenReturn( false );
|
||||
|
||||
SqlExceptionHelper sqlExceptionHelper = Mockito.mock( SqlExceptionHelper.class );
|
||||
|
|
|
@ -15,13 +15,9 @@ import javax.persistence.Id;
|
|||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.hibernate.test.util.ReflectionUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
@ -51,7 +47,7 @@ public abstract class AbstractSkipAutoCommitTest extends BaseEntityManagerFuncti
|
|||
Map config = super.getConfig();
|
||||
|
||||
config.put( AvailableSettings.DATASOURCE, dataSource() );
|
||||
config.put( AvailableSettings.SKIP_AUTOCOMMIT_CHECK, Boolean.TRUE );
|
||||
config.put( AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, Boolean.TRUE );
|
||||
config.put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider );
|
||||
|
||||
return config;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.resource.transaction.jdbc;
|
||||
package org.hibernate.test.hikaricp;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
@ -40,7 +40,7 @@ public class HikariCPSkipAutoCommitTest extends BaseCoreFunctionalTestCase {
|
|||
org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
configuration.getProperties().put( AvailableSettings.SKIP_AUTOCOMMIT_CHECK, Boolean.TRUE );
|
||||
configuration.getProperties().put( AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, Boolean.TRUE );
|
||||
configuration.getProperties().put( "hibernate.hikari.autoCommit", Boolean.FALSE.toString() );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue