HHH-14867 Don't forcefully acquire connection for transaction handling

This commit is contained in:
Christian Beikov 2024-02-16 13:48:21 +01:00
parent 897b87bca6
commit 4ac91f793f
17 changed files with 53 additions and 9 deletions

View File

@ -83,7 +83,12 @@ public abstract class AbstractLogicalConnectionImplementor implements LogicalCon
public void commit() { public void commit() {
try { try {
log.trace( "Preparing to commit transaction via JDBC Connection.commit()" ); log.trace( "Preparing to commit transaction via JDBC Connection.commit()" );
getConnectionForTransactionManagement().commit(); if ( isPhysicallyConnected() ) {
getConnectionForTransactionManagement().commit();
}
else {
errorIfClosed();
}
status = TransactionStatus.COMMITTED; status = TransactionStatus.COMMITTED;
log.trace( "Transaction committed via JDBC Connection.commit()" ); log.trace( "Transaction committed via JDBC Connection.commit()" );
} }
@ -118,7 +123,12 @@ public abstract class AbstractLogicalConnectionImplementor implements LogicalCon
public void rollback() { public void rollback() {
try { try {
log.trace( "Preparing to rollback transaction via JDBC Connection.rollback()" ); log.trace( "Preparing to rollback transaction via JDBC Connection.rollback()" );
getConnectionForTransactionManagement().rollback(); if ( isPhysicallyConnected() ) {
getConnectionForTransactionManagement().rollback();
}
else {
errorIfClosed();
}
status = TransactionStatus.ROLLED_BACK; status = TransactionStatus.ROLLED_BACK;
log.trace( "Transaction rolled-back via JDBC Connection.rollback()" ); log.trace( "Transaction rolled-back via JDBC Connection.rollback()" );
} }

View File

@ -285,8 +285,7 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
@Override @Override
public void rollback() { public void rollback() {
try { try {
TransactionStatus status = jdbcResourceTransaction.getStatus(); if ( rollbackOnly || jdbcResourceTransaction.getStatus() == TransactionStatus.ACTIVE ) {
if ( ( rollbackOnly && status != TransactionStatus.NOT_ACTIVE ) || status == TransactionStatus.ACTIVE ) {
jdbcResourceTransaction.rollback(); jdbcResourceTransaction.rollback();
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( false ); JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( false );
} }

View File

@ -13,9 +13,9 @@ import org.hibernate.stat.Statistics;
import org.hibernate.testing.orm.jdbc.PreparedStatementSpyConnectionProvider; import org.hibernate.testing.orm.jdbc.PreparedStatementSpyConnectionProvider;
import org.hibernate.testing.orm.jdbc.PreparedStatementSpyConnectionProviderSettingProvider; import org.hibernate.testing.orm.jdbc.PreparedStatementSpyConnectionProviderSettingProvider;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.Jpa; import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.Setting;
import org.hibernate.testing.orm.junit.SettingProvider; import org.hibernate.testing.orm.junit.SettingProvider;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -41,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
settingName = AvailableSettings.CONNECTION_PROVIDER, settingName = AvailableSettings.CONNECTION_PROVIDER,
provider = PreparedStatementSpyConnectionProviderSettingProvider.class) provider = PreparedStatementSpyConnectionProviderSettingProvider.class)
}, },
integrationSettings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, value = "true"),
generateStatistics = true generateStatistics = true
) )
@JiraKey( value = "HHH-14867" ) @JiraKey( value = "HHH-14867" )
@ -66,7 +67,6 @@ public class L2CacheAccessNoCommitTest {
} }
@Test @Test
@FailureExpected
public void test(EntityManagerFactoryScope scope) { public void test(EntityManagerFactoryScope scope) {
final PreparedStatementSpyConnectionProvider connectionProvider = final PreparedStatementSpyConnectionProvider connectionProvider =
(PreparedStatementSpyConnectionProvider) scope.getEntityManagerFactory().getProperties() (PreparedStatementSpyConnectionProvider) scope.getEntityManagerFactory().getProperties()

View File

@ -61,6 +61,7 @@ public class LazyLoadingConnectionCloseTest extends EntityManagerFactoryBasedFun
); );
options.put( AvailableSettings.AUTOCOMMIT, "false" ); options.put( AvailableSettings.AUTOCOMMIT, "false" );
options.put( AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, "false" );
connectionProvider = new ConnectionCheckingConnectionProvider(); connectionProvider = new ConnectionCheckingConnectionProvider();
options.put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider ); options.put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider );

View File

@ -44,6 +44,8 @@ public class ConnectionsReleaseAutoCommitTest {
connectionProvider.clear(); connectionProvider.clear();
scope.inTransaction( entityManager -> { scope.inTransaction( entityManager -> {
// Force connection acquisition
entityManager.createQuery( "select 1" ).getResultList();
assertEquals( 1, connectionProvider.getTotalOpenedConnectionCount() ); assertEquals( 1, connectionProvider.getTotalOpenedConnectionCount() );
Thing thing = new Thing(); Thing thing = new Thing();
thing.setId( 1 ); thing.setId( 1 );

View File

@ -66,6 +66,8 @@ public class DisableDiscardPersistenceContextOnCloseTest {
try { try {
entityManager.getTransaction().begin(); entityManager.getTransaction().begin();
// Force connection acquisition
entityManager.createQuery( "select 1" ).getResultList();
entityManager.persist( wallet ); entityManager.persist( wallet );
assertEquals( 1, connectionProvider.getAcquiredConnections().size() ); assertEquals( 1, connectionProvider.getAcquiredConnections().size() );
entityManager.close(); entityManager.close();

View File

@ -58,6 +58,8 @@ public class EnableDiscardPersistenceContextOnCloseTest {
try { try {
entityManager.getTransaction().begin(); entityManager.getTransaction().begin();
// Force connection acquisition
entityManager.createQuery( "select 1" ).getResultList();
entityManager.persist( wallet ); entityManager.persist( wallet );
assertEquals( 1, connectionProvider.getAcquiredConnections().size() ); assertEquals( 1, connectionProvider.getAcquiredConnections().size() );
entityManager.close(); entityManager.close();

View File

@ -70,6 +70,8 @@ public class TransactionCommitFailureTest {
try { try {
em.getTransaction().begin(); em.getTransaction().begin();
// Force connection acquisition
em.createQuery( "select 1" ).getResultList();
transactionFailureTrigger.set( true ); transactionFailureTrigger.set( true );
em.getTransaction().commit(); em.getTransaction().commit();
} }
@ -92,6 +94,8 @@ public class TransactionCommitFailureTest {
EntityManager em = emf.createEntityManager(); EntityManager em = emf.createEntityManager();
try { try {
em.getTransaction().begin(); em.getTransaction().begin();
// Force connection acquisition
em.createQuery( "select 1" ).getResultList();
assertEquals( true, connectionIsOpen.get() ); assertEquals( true, connectionIsOpen.get() );
transactionFailureTrigger.set( true ); transactionFailureTrigger.set( true );
em.getTransaction().rollback(); em.getTransaction().rollback();

View File

@ -41,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.fail;
integrationSettings = { integrationSettings = {
@Setting(name = AvailableSettings.JPA_TRANSACTION_TYPE, value = "JTA"), @Setting(name = AvailableSettings.JPA_TRANSACTION_TYPE, value = "JTA"),
@Setting(name = AvailableSettings.JPA_TRANSACTION_COMPLIANCE, value = "true"), @Setting(name = AvailableSettings.JPA_TRANSACTION_COMPLIANCE, value = "true"),
@Setting(name = AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, value = "true"),
@Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "50") @Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "50")
}, },
settingProviders = { settingProviders = {

View File

@ -42,6 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
integrationSettings = { integrationSettings = {
@Setting(name = AvailableSettings.JPA_TRANSACTION_TYPE, value = "JTA"), @Setting(name = AvailableSettings.JPA_TRANSACTION_TYPE, value = "JTA"),
@Setting(name = AvailableSettings.JPA_TRANSACTION_COMPLIANCE, value = "true"), @Setting(name = AvailableSettings.JPA_TRANSACTION_COMPLIANCE, value = "true"),
@Setting(name = AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, value = "true"),
@Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "50") @Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "50")
}, },
settingProviders = { settingProviders = {

View File

@ -59,6 +59,7 @@ import static org.junit.jupiter.api.Assertions.assertSame;
@Setting(name = AvailableSettings.FLUSH_BEFORE_COMPLETION, value = "true"), @Setting(name = AvailableSettings.FLUSH_BEFORE_COMPLETION, value = "true"),
@Setting(name = AvailableSettings.USE_QUERY_CACHE, value = "true"), @Setting(name = AvailableSettings.USE_QUERY_CACHE, value = "true"),
@Setting(name = AvailableSettings.CACHE_REGION_PREFIX, value = ""), @Setting(name = AvailableSettings.CACHE_REGION_PREFIX, value = ""),
@Setting(name = AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, value = "true"),
@Setting(name = "javax.persistence.transactionType", value = "JTA"), @Setting(name = "javax.persistence.transactionType", value = "JTA"),
}, },

View File

@ -502,6 +502,9 @@ public class UnionSubclassTest extends BaseSessionFactoryFunctionalTest {
// connections. // connections.
inTransaction( s1 -> { inTransaction( s1 -> {
// Force connection acquisition
s1.createQuery( "select 1" ).getResultList();
// Transaction used by s1 is already started. // Transaction used by s1 is already started.
// Assert that the Connection is already physically connected. // Assert that the Connection is already physically connected.
assertTrue( s1.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected() ); assertTrue( s1.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected() );
@ -520,6 +523,8 @@ public class UnionSubclassTest extends BaseSessionFactoryFunctionalTest {
// for a bulk operation. // for a bulk operation.
inTransaction( s2 -> { inTransaction( s2 -> {
// Force connection acquisition
s2.createQuery( "select 1" ).getResultList();
// Check same assertions for s2 as was done for s1. // Check same assertions for s2 as was done for s1.
assertTrue( s2.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected() ); assertTrue( s2.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected() );
assertEquals( assertEquals(

View File

@ -22,6 +22,10 @@ public final class TestingJtaBootstrap {
public static void prepare(Map<String,Object> configValues) { public static void prepare(Map<String,Object> configValues) {
configValues.put( AvailableSettings.JTA_PLATFORM, TestingJtaPlatformImpl.INSTANCE ); configValues.put( AvailableSettings.JTA_PLATFORM, TestingJtaPlatformImpl.INSTANCE );
configValues.put( AvailableSettings.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() ); configValues.put( AvailableSettings.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() );
configValues.put(
AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT,
Boolean.TRUE
);
configValues.put( "javax.persistence.transactionType", "JTA" ); configValues.put( "javax.persistence.transactionType", "JTA" );
} }
@ -29,6 +33,10 @@ public final class TestingJtaBootstrap {
registryBuilder.applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ); registryBuilder.applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" );
registryBuilder.applySetting( AvailableSettings.JTA_PLATFORM, TestingJtaPlatformImpl.INSTANCE ); registryBuilder.applySetting( AvailableSettings.JTA_PLATFORM, TestingJtaPlatformImpl.INSTANCE );
registryBuilder.applySetting( AvailableSettings.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() ); registryBuilder.applySetting( AvailableSettings.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() );
registryBuilder.applySetting(
AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT,
Boolean.TRUE
);
registryBuilder.applySetting( "javax.persistence.transactionType", "JTA" ); registryBuilder.applySetting( "javax.persistence.transactionType", "JTA" );
} }

View File

@ -84,8 +84,8 @@ public abstract class BaseSessionFactoryFunctionalTest
@Override @Override
public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder ssrBuilder) { public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder ssrBuilder) {
ssrBuilder.applySetting( AvailableSettings.HBM2DDL_AUTO, exportSchema() ? "create-drop" : "none" ); ssrBuilder.applySetting( AvailableSettings.HBM2DDL_AUTO, exportSchema() ? "create-drop" : "none" );
ServiceRegistryUtil.applySettings( ssrBuilder );
applySettings( ssrBuilder ); applySettings( ssrBuilder );
ServiceRegistryUtil.applySettings( ssrBuilder );
return ssrBuilder.build(); return ssrBuilder.build();
} }

View File

@ -168,7 +168,6 @@ public class EntityManagerFactoryExtension
integrationSettings.put( PersistentTableStrategy.DROP_ID_TABLES, "true" ); integrationSettings.put( PersistentTableStrategy.DROP_ID_TABLES, "true" );
integrationSettings.put( GlobalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" ); integrationSettings.put( GlobalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" );
integrationSettings.put( LocalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" ); integrationSettings.put( LocalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" );
ServiceRegistryUtil.applySettings( integrationSettings );
for ( int i = 0; i < emfAnn.integrationSettings().length; i++ ) { for ( int i = 0; i < emfAnn.integrationSettings().length; i++ ) {
final Setting setting = emfAnn.integrationSettings()[i]; final Setting setting = emfAnn.integrationSettings()[i];
integrationSettings.put( setting.name(), setting.value() ); integrationSettings.put( setting.name(), setting.value() );
@ -194,6 +193,7 @@ public class EntityManagerFactoryExtension
integrationSettings.put( AvailableSettings.STATEMENT_INSPECTOR, new SQLStatementInspector() ); integrationSettings.put( AvailableSettings.STATEMENT_INSPECTOR, new SQLStatementInspector() );
} }
ServiceRegistryUtil.applySettings( integrationSettings );
final EntityManagerFactoryScopeImpl scope = new EntityManagerFactoryScopeImpl( pui, integrationSettings ); final EntityManagerFactoryScopeImpl scope = new EntityManagerFactoryScopeImpl( pui, integrationSettings );
locateExtensionStore( testInstance, context ).put( EMF_KEY, scope ); locateExtensionStore( testInstance, context ).put( EMF_KEY, scope );

View File

@ -196,12 +196,12 @@ public class ServiceRegistryExtension
ssrb.applySetting( PersistentTableStrategy.DROP_ID_TABLES, "true" ); ssrb.applySetting( PersistentTableStrategy.DROP_ID_TABLES, "true" );
ssrb.applySetting( GlobalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" ); ssrb.applySetting( GlobalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" );
ssrb.applySetting( LocalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" ); ssrb.applySetting( LocalTemporaryTableMutationStrategy.DROP_ID_TABLES, "true" );
ServiceRegistryUtil.applySettings( ssrb.getSettings() );
if ( ssrAnnRef.isPresent() ) { if ( ssrAnnRef.isPresent() ) {
final ServiceRegistry serviceRegistryAnn = ssrAnnRef.get(); final ServiceRegistry serviceRegistryAnn = ssrAnnRef.get();
configureServices( serviceRegistryAnn, ssrb ); configureServices( serviceRegistryAnn, ssrb );
} }
ServiceRegistryUtil.applySettings( ssrb.getSettings() );
return ssrb.build(); return ssrb.build();
} }

View File

@ -38,6 +38,10 @@ public class ServiceRegistryUtil {
AvailableSettings.CONNECTION_PROVIDER, AvailableSettings.CONNECTION_PROVIDER,
SharedDriverManagerConnectionProviderImpl.getInstance() SharedDriverManagerConnectionProviderImpl.getInstance()
); );
builder.applySetting(
AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT,
Boolean.TRUE
);
} }
return builder; return builder;
} }
@ -49,6 +53,10 @@ public class ServiceRegistryUtil {
AvailableSettings.CONNECTION_PROVIDER, AvailableSettings.CONNECTION_PROVIDER,
SharedDriverManagerConnectionProviderImpl.getInstance() SharedDriverManagerConnectionProviderImpl.getInstance()
); );
( (Map<Object, Object>) properties ).put(
AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT,
Boolean.TRUE
);
} }
} }