diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index 6be365608cc..fb7bc9a1748 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.orm.jpa; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -77,7 +78,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { "org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform", }; private final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider; - private final Collection metadataProviders; + + private DataSourcePoolMetadataProvider poolMetadataProvider; HibernateJpaConfiguration(DataSource dataSource, JpaProperties jpaProperties, ObjectProvider jtaTransactionManager, @@ -88,7 +90,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { transactionManagerCustomizers); this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider( providers.getIfAvailable(Collections::emptyList)); - this.metadataProviders = metadataProviders.getIfAvailable(); + this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider( + metadataProviders.getIfAvailable()); } @Override @@ -136,17 +139,18 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { } private void configureProviderDisablesAutocommit(Map vendorProperties) { - CompositeDataSourcePoolMetadataProvider poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider( - this.metadataProviders); - DataSourcePoolMetadata poolMetadata = poolMetadataProvider - .getDataSourcePoolMetadata(getDataSource()); - if (poolMetadata != null - && Boolean.FALSE.equals(poolMetadata.getDefaultAutoCommit()) - && getJtaTransactionManager() == null) { + if (isDataSourceAutoCommitDisabled() && !isJta()) { vendorProperties.put(PROVIDER_DISABLES_AUTOCOMMIT, "true"); } } + private boolean isDataSourceAutoCommitDisabled() { + DataSourcePoolMetadata poolMetadata = this.poolMetadataProvider + .getDataSourcePoolMetadata(getDataSource()); + return poolMetadata != null + && Boolean.FALSE.equals(poolMetadata.getDefaultAutoCommit()); + } + private boolean runningOnWebSphere() { return ClassUtils.isPresent( "com.ibm.websphere.jtaextensions." + "ExtendedJTATransaction", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index c91b76a3be7..18f0fd44b0e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -33,6 +33,7 @@ import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; +import com.zaxxer.hikari.HikariDataSource; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.junit.Test; @@ -52,6 +53,7 @@ import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import static org.mockito.Mockito.mock; /** @@ -75,12 +77,12 @@ public class HibernateJpaAutoConfigurationTests contextRunner().withPropertyValues("spring.datasource.data:classpath:/city.sql", // Missing: "spring.datasource.schema:classpath:/ddl.sql").run((context) -> { - assertThat(context).hasFailed(); - assertThat(context.getStartupFailure()) - .hasMessageContaining("ddl.sql"); - assertThat(context.getStartupFailure()) - .hasMessageContaining("spring.datasource.schema"); - }); + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure()) + .hasMessageContaining("ddl.sql"); + assertThat(context.getStartupFailure()) + .hasMessageContaining("spring.datasource.schema"); + }); } @Test @@ -105,7 +107,7 @@ public class HibernateJpaAutoConfigurationTests "spring.datasource.data:classpath:/city.sql") .run((context) -> assertThat( context.getBean(TestInitializedJpaConfiguration.class).called) - .isTrue()); + .isTrue()); } @Test @@ -164,7 +166,7 @@ public class HibernateJpaAutoConfigurationTests .getJpaPropertyMap(); assertThat((String) jpaPropertyMap .get("hibernate.transaction.jta.platform")) - .isEqualTo(TestJtaPlatform.class.getName()); + .isEqualTo(TestJtaPlatform.class.getName()); }); } @@ -194,6 +196,62 @@ public class HibernateJpaAutoConfigurationTests }); } + @Test + public void providerDisablesAutoCommitIsConfigured() { + contextRunner().withPropertyValues( + "spring.datasource.type:" + HikariDataSource.class.getName(), + "spring.datasource.hikari.auto-commit:false").run((context) -> { + Map jpaProperties = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getJpaPropertyMap(); + assertThat(jpaProperties).contains(entry( + "hibernate.connection.provider_disables_autocommit", "true")); + }); + } + + @Test + public void providerDisablesAutoCommitIsNotConfiguredIfAutoCommitIsEnabled() { + contextRunner().withPropertyValues( + "spring.datasource.type:" + HikariDataSource.class.getName(), + "spring.datasource.hikari.auto-commit:true").run((context) -> { + Map jpaProperties = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getJpaPropertyMap(); + assertThat(jpaProperties).doesNotContainKeys( + "hibernate.connection.provider_disables_autocommit"); + }); + } + + @Test + public void providerDisablesAutoCommitIsNotConfiguredIfPropertyIsSet() { + contextRunner().withPropertyValues( + "spring.datasource.type:" + HikariDataSource.class.getName(), + "spring.datasource.hikari.auto-commit:false", + "spring.jpa.properties.hibernate.connection.provider_disables_autocommit=false" + ).run((context) -> { + Map jpaProperties = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getJpaPropertyMap(); + assertThat(jpaProperties).contains(entry( + "hibernate.connection.provider_disables_autocommit", "false")); + }); + } + + @Test + public void providerDisablesAutoCommitIsNotConfiguredWihJta() { + contextRunner() + .withConfiguration(AutoConfigurations.of(JtaAutoConfiguration.class)) + .withPropertyValues( + "spring.datasource.type:" + HikariDataSource.class.getName(), + "spring.datasource.hikari.auto-commit:false").run((context) -> { + Map jpaProperties = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getJpaPropertyMap(); + assertThat(jpaProperties).doesNotContainKeys( + "hibernate.connection.provider_disables_autocommit"); + }); + } + @Configuration @TestAutoConfigurationPackage(City.class) static class TestInitializedJpaConfiguration { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java index 17c6ce18459..e401cb349f8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java @@ -86,6 +86,9 @@ public abstract class AbstractDataSourcePoolMetadataTests initializeBuilder() { return DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver") .url("jdbc:hsqldb:mem:test").username("sa"); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java index 2cc78162776..ec28aa4a59d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java @@ -81,6 +81,14 @@ public class CommonsDbcp2DataSourcePoolMetadataTests .isEqualTo("SELECT FROM FOO"); } + @Override + public void getDefaultAutoCommit() { + BasicDataSource dataSource = createDataSource(); + dataSource.setDefaultAutoCommit(false); + assertThat(new CommonsDbcp2DataSourcePoolMetadata(dataSource) + .getDefaultAutoCommit()).isFalse(); + } + private CommonsDbcp2DataSourcePoolMetadata createDataSourceMetadata(int minSize, int maxSize) { BasicDataSource dataSource = createDataSource(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java index 45921713d55..4b8462def38 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java @@ -50,6 +50,14 @@ public class HikariDataSourcePoolMetadataTests .isEqualTo("SELECT FROM FOO"); } + @Override + public void getDefaultAutoCommit() { + HikariDataSource dataSource = createDataSource(0, 4); + dataSource.setAutoCommit(false); + assertThat(new HikariDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()) + .isFalse(); + } + private HikariDataSource createDataSource(int minSize, int maxSize) { HikariDataSource dataSource = initializeBuilder().type(HikariDataSource.class) .build(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java index c013556da14..403f70a9ea5 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java @@ -50,6 +50,14 @@ public class TomcatDataSourcePoolMetadataTests .isEqualTo("SELECT FROM FOO"); } + @Override + public void getDefaultAutoCommit() { + DataSource dataSource = createDataSource(0, 4); + dataSource.setDefaultAutoCommit(false); + assertThat(new TomcatDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()) + .isFalse(); + } + private DataSource createDataSource(int minSize, int maxSize) { DataSource dataSource = initializeBuilder().type(DataSource.class).build(); dataSource.setMinIdle(minSize);