Merge pull request #9737 from candrews:autocommit
* pr/9737: Polish "When pool autocommit is disabled, inform Hibernate" When pool autocommit is disabled, inform Hibernate
This commit is contained in:
@@ -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;
|
||||
@@ -30,6 +31,9 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
||||
import org.springframework.boot.jdbc.SchemaManagementProvider;
|
||||
import org.springframework.boot.jdbc.metadata.CompositeDataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata;
|
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jndi.JndiLocatorDelegate;
|
||||
@@ -56,6 +60,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";
|
||||
|
||||
private static final String PROVIDER_DISABLES_AUTOCOMMIT = "hibernate.connection.provider_disables_autocommit";
|
||||
|
||||
/**
|
||||
* {@code NoJtaPlatform} implementations for various Hibernate versions.
|
||||
*/
|
||||
@@ -73,14 +79,19 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
private final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider;
|
||||
|
||||
private DataSourcePoolMetadataProvider poolMetadataProvider;
|
||||
|
||||
HibernateJpaConfiguration(DataSource dataSource, JpaProperties jpaProperties,
|
||||
ObjectProvider<JtaTransactionManager> jtaTransactionManager,
|
||||
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
|
||||
ObjectProvider<Collection<DataSourcePoolMetadataProvider>> metadataProviders,
|
||||
ObjectProvider<List<SchemaManagementProvider>> providers) {
|
||||
super(dataSource, jpaProperties, jtaTransactionManager,
|
||||
transactionManagerCustomizers);
|
||||
this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(
|
||||
providers.getIfAvailable(Collections::emptyList));
|
||||
this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider(
|
||||
metadataProviders.getIfAvailable());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,6 +114,9 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
|
||||
if (!vendorProperties.containsKey(JTA_PLATFORM)) {
|
||||
configureJtaPlatform(vendorProperties);
|
||||
}
|
||||
if (!vendorProperties.containsKey(PROVIDER_DISABLES_AUTOCOMMIT)) {
|
||||
configureProviderDisablesAutocommit(vendorProperties);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureJtaPlatform(Map<String, Object> vendorProperties)
|
||||
@@ -124,6 +138,19 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private void configureProviderDisablesAutocommit(Map<String, Object> vendorProperties) {
|
||||
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",
|
||||
|
||||
@@ -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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> jpaProperties = context
|
||||
.getBean(LocalContainerEntityManagerFactoryBean.class)
|
||||
.getJpaPropertyMap();
|
||||
assertThat(jpaProperties).doesNotContainKeys(
|
||||
"hibernate.connection.provider_disables_autocommit");
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
static class TestInitializedJpaConfiguration {
|
||||
|
||||
@@ -53,4 +53,9 @@ public class CommonsDbcp2DataSourcePoolMetadata
|
||||
return getDataSource().getValidationQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getDefaultAutoCommit() {
|
||||
return getDataSource().getDefaultAutoCommit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,4 +71,12 @@ public interface DataSourcePoolMetadata {
|
||||
*/
|
||||
String getValidationQuery();
|
||||
|
||||
/**
|
||||
* The default auto-commit state of connections created by this pool.
|
||||
* If not set ({@code null}), default is JDBC driver default
|
||||
* (If set to null then the java.sql.Connection.setAutoCommit(boolean) method will not be called.)
|
||||
* @return the default auto-commit state or {@code null}
|
||||
*/
|
||||
Boolean getDefaultAutoCommit();
|
||||
|
||||
}
|
||||
|
||||
@@ -66,4 +66,9 @@ public class HikariDataSourcePoolMetadata
|
||||
return getDataSource().getConnectionTestQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getDefaultAutoCommit() {
|
||||
return getDataSource().isAutoCommit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,4 +53,9 @@ public class TomcatDataSourcePoolMetadata
|
||||
return getDataSource().getValidationQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getDefaultAutoCommit() {
|
||||
return getDataSource().isDefaultAutoCommit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,6 +86,9 @@ public abstract class AbstractDataSourcePoolMetadataTests<D extends AbstractData
|
||||
@Test
|
||||
public abstract void getValidationQuery();
|
||||
|
||||
@Test
|
||||
public abstract void getDefaultAutoCommit();
|
||||
|
||||
protected DataSourceBuilder<?> initializeBuilder() {
|
||||
return DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||
.url("jdbc:hsqldb:mem:test").username("sa");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user