Attempt to detect ddl-auto mode only if necessary

This commit defers the resolution of the default ddl auto mode only when
it is absolutely necessary. This prevents Spring Boot to attempt to get
a connection when it isn't necessary

Closes gh-12374
This commit is contained in:
Stephane Nicoll 2018-03-07 12:00:00 +01:00
parent 317b51f2ad
commit 0207b816d9
6 changed files with 69 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.orm.jpa;
import java.util.Map;
import java.util.function.Supplier;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@ -90,8 +91,9 @@ class DataSourceInitializedPublisher implements BeanPostProcessor {
if (this.properties == null) {
return true; // better safe than sorry
}
String defaultDdlAuto = (EmbeddedDatabaseConnection.isEmbedded(dataSource)
? "create-drop" : "none");
Supplier<String> defaultDdlAuto = () ->
EmbeddedDatabaseConnection.isEmbedded(dataSource) ? "create-drop"
: "none";
Map<String, Object> hibernate = this.properties
.getHibernateProperties(new HibernateSettings().ddlAuto(defaultDdlAuto));
if (hibernate.containsKey("hibernate.hbm2ddl.auto")) {

View File

@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import javax.sql.DataSource;
@ -116,7 +117,7 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
@Override
protected Map<String, Object> getVendorProperties() {
String defaultDdlMode = this.defaultDdlAutoProvider
Supplier<String> defaultDdlMode = () -> this.defaultDdlAutoProvider
.getDefaultDdlAuto(getDataSource());
return new LinkedHashMap<>(getProperties()
.getHibernateProperties(new HibernateSettings().ddlAuto(defaultDdlMode)

View File

@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.orm.jpa;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Supplier;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
@ -30,7 +31,7 @@ import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
*/
public class HibernateSettings {
private String ddlAuto;
private Supplier<String> ddlAuto;
private ImplicitNamingStrategy implicitNamingStrategy;
@ -38,13 +39,25 @@ public class HibernateSettings {
private Collection<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers;
public HibernateSettings ddlAuto(String ddlAuto) {
public HibernateSettings ddlAuto(Supplier<String> ddlAuto) {
this.ddlAuto = ddlAuto;
return this;
}
/**
* Specify the default ddl auto value to use.
* @param ddlAuto the default ddl auto if none is provided
* @return this instance
* @see #ddlAuto(Supplier)
* @deprecated as of 2.0.1 in favour of {@link #ddlAuto(Supplier)}
*/
@Deprecated
public HibernateSettings ddlAuto(String ddlAuto) {
return ddlAuto(() -> ddlAuto);
}
public String getDdlAuto() {
return this.ddlAuto;
return (this.ddlAuto != null ? this.ddlAuto.get() : null);
}
public HibernateSettings implicitNamingStrategy(

View File

@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Provider;
import javax.sql.DataSource;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
@ -217,7 +218,7 @@ public class JpaProperties {
getNaming().applyNamingStrategies(result,
settings.getImplicitNamingStrategy(),
settings.getPhysicalNamingStrategy());
String ddlAuto = determineDdlAuto(existing, settings.getDdlAuto());
String ddlAuto = determineDdlAuto(existing, settings::getDdlAuto);
if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) {
result.put("hibernate.hbm2ddl.auto", ddlAuto);
}
@ -243,11 +244,13 @@ public class JpaProperties {
}
private String determineDdlAuto(Map<String, String> existing,
String defaultDdlAuto) {
String ddlAuto = (this.ddlAuto != null ? this.ddlAuto : defaultDdlAuto);
if (!existing.containsKey("hibernate.hbm2ddl.auto")
&& !"none".equals(ddlAuto)) {
return ddlAuto;
Provider<String> defaultDdlAuto) {
if (!existing.containsKey("hibernate.hbm2ddl.auto")) {
String ddlAuto = (this.ddlAuto != null ? this.ddlAuto
: defaultDdlAuto.get());
if (!"none".equals(ddlAuto)) {
return ddlAuto;
}
}
if (existing.containsKey("hibernate.hbm2ddl.auto")) {
return existing.get("hibernate.hbm2ddl.auto");

View File

@ -69,7 +69,7 @@ public class CustomHibernateJpaAutoConfigurationTests {
.run((context) -> {
JpaProperties bean = context.getBean(JpaProperties.class);
Map<String, Object> hibernateProperties = bean.getHibernateProperties(
new HibernateSettings().ddlAuto("create-drop"));
new HibernateSettings());
assertThat(hibernateProperties.get("hibernate.ejb.naming_strategy"))
.isNull();
});

View File

@ -22,6 +22,7 @@ import java.sql.SQLException;
import java.util.Collections;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.sql.DataSource;
@ -60,7 +61,7 @@ public class JpaPropertiesTests {
public void noCustomNamingStrategy() {
this.contextRunner.run(assertJpaProperties((properties) -> {
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(new HibernateSettings().ddlAuto("none"));
.getHibernateProperties(new HibernateSettings());
assertThat(hibernateProperties)
.doesNotContainKeys("hibernate.ejb.naming_strategy");
assertThat(hibernateProperties).containsEntry(
@ -80,7 +81,7 @@ public class JpaPropertiesTests {
.run(assertJpaProperties((properties) -> {
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(
new HibernateSettings().ddlAuto("none"));
new HibernateSettings());
assertThat(hibernateProperties).contains(
entry("hibernate.implicit_naming_strategy",
"com.example.Implicit"),
@ -97,7 +98,7 @@ public class JpaPropertiesTests {
ImplicitNamingStrategy implicitStrategy = mock(ImplicitNamingStrategy.class);
PhysicalNamingStrategy physicalStrategy = mock(PhysicalNamingStrategy.class);
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(new HibernateSettings().ddlAuto("none")
.getHibernateProperties(new HibernateSettings()
.implicitNamingStrategy(implicitStrategy)
.physicalNamingStrategy(physicalStrategy));
assertThat(hibernateProperties).contains(
@ -120,7 +121,7 @@ public class JpaPropertiesTests {
PhysicalNamingStrategy.class);
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(
new HibernateSettings().ddlAuto("none")
new HibernateSettings()
.implicitNamingStrategy(implicitStrategy)
.physicalNamingStrategy(physicalStrategy));
assertThat(hibernateProperties).contains(
@ -154,7 +155,7 @@ public class JpaPropertiesTests {
};
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(
new HibernateSettings().ddlAuto("none")
new HibernateSettings()
.implicitNamingStrategy(implicitStrategy)
.physicalNamingStrategy(physicalStrategy)
.hibernatePropertiesCustomizers(
@ -177,7 +178,7 @@ public class JpaPropertiesTests {
.run(assertJpaProperties((properties) -> {
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(
new HibernateSettings().ddlAuto("none"));
new HibernateSettings());
// You can override them as we don't provide any default
assertThat(hibernateProperties).contains(
entry("hibernate.implicit_naming_strategy",
@ -193,7 +194,7 @@ public class JpaPropertiesTests {
public void useNewIdGeneratorMappingsDefault() {
this.contextRunner.run(assertJpaProperties((properties) -> {
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(new HibernateSettings().ddlAuto("none"));
.getHibernateProperties(new HibernateSettings());
assertThat(hibernateProperties).containsEntry(
AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true");
}));
@ -207,7 +208,7 @@ public class JpaPropertiesTests {
.run(assertJpaProperties((properties) -> {
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(
new HibernateSettings().ddlAuto("none"));
new HibernateSettings());
assertThat(hibernateProperties).containsEntry(
AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "false");
}));
@ -248,6 +249,33 @@ public class JpaPropertiesTests {
}));
}
@Test
public void defaultDdlAutoIsNotInvokedIfPropertyIsSet() {
this.contextRunner
.withPropertyValues("spring.jpa.hibernate.ddl-auto=validate")
.run(assertDefaultDdlAutoNotInvoked("validate"));
}
@Test
public void defaultDdlAutoIsNotInvokedIfHibernateSpecificPropertyIsSet() {
this.contextRunner
.withPropertyValues("spring.jpa.properties.hibernate.hbm2ddl.auto=create")
.run(assertDefaultDdlAutoNotInvoked("create"));
}
private ContextConsumer<AssertableApplicationContext> assertDefaultDdlAutoNotInvoked(
String expectedDdlAuto) {
return assertJpaProperties((properties) -> {
Supplier<String> ddlAutoSupplier = mock(Supplier.class);
Map<String, Object> hibernateProperties = properties
.getHibernateProperties(new HibernateSettings()
.ddlAuto(ddlAutoSupplier));
assertThat(hibernateProperties).containsEntry(
"hibernate.hbm2ddl.auto", expectedDdlAuto);
verify(ddlAutoSupplier, never()).get();
});
}
@Test
public void determineDatabaseWithUnknownUrl() {
this.contextRunner.run(assertJpaProperties((properties) -> {