diff --git a/docs/howto.md b/docs/howto.md index b96217500ee..61d8d6e82de 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -901,14 +901,16 @@ enables it by default and loads SQL from the standard locations `schema.sql` and `data.sql` (in the root of the classpath). In addition Spring Boot will load a file `schema-${platform}.sql` where `platform` is the vendor name of the database (`hsqldb`, `h2, -`oracle`, `mysql`, `postgresql` etc.). Spring Boot *disables* the -failfast feature of the Spring JDBC initializer, so if the scripts -cause exceptions they will be logged, but the application will still -start. This is so that they can be used as "poor man's migrations" -(inserts that fail mean that the data is already there, so no need to -fail for instance), but it does mean that you need to test the state -of your database on startup if you want to be sure that it was -successful (or else monitor the Spring JDBC DEBUG logs). +`oracle`, `mysql`, `postgresql` etc.). Spring Boot enables the +failfast feature of the Spring JDBC initializer by default, so if +the scripts cause exceptions the application will fail. + +To disable the failfast you can set +`spring.datasource.continueOnError=true`. This can be useful once an +application has matured and been deployed a few times, since the +scripts can act as "poor man's migrations" - inserts that fail mean +that the data is already there, so there would be no need to prevent +the application from running, for instance. ### Higher Level Migration Tools diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java index 11d2345b686..88e8129bd44 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java @@ -106,13 +106,15 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { .getResources(schemaLocation))); } + boolean continueOnError = this.environment.getProperty("continueOnError", + Boolean.class, false); boolean exists = false; ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); for (Resource resource : resources) { if (resource.exists()) { exists = true; populator.addScript(resource); - populator.setContinueOnError(true); + populator.setContinueOnError(continueOnError); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index 0188d16df75..56a564e83b9 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -24,11 +24,13 @@ import java.sql.SQLFeatureNotSupportedException; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.Random; import java.util.logging.Logger; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; @@ -56,6 +58,13 @@ public class DataSourceAutoConfigurationTests { private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + @Before + public void init() { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.initialize:false", + "spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt()); + } + @Test public void testDefaultDataSourceExists() throws Exception { this.context.register(DataSourceAutoConfiguration.class, @@ -85,8 +94,7 @@ public class DataSourceAutoConfigurationTests { .addEnvironment( this.context, "spring.datasource.driverClassName:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfigurationTests$DatabaseDriver", - "spring.datasource.url:jdbc:foo://localhost", - "spring.datasource.initialize:false"); + "spring.datasource.url:jdbc:foo://localhost"); this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); @@ -141,6 +149,8 @@ public class DataSourceAutoConfigurationTests { @Test public void testDataSourceInitialized() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.initialize:true"); this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); @@ -172,16 +182,17 @@ public class DataSourceAutoConfigurationTests { @Test public void testDataSourceInitializedWithMultipleScripts() throws Exception { - this.context.register(DataSourceAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - Map map = new HashMap(); - map.put(DataSourceAutoConfiguration.CONFIGURATION_PREFIX + ".schema", - ClassUtils.addResourcePathToPackagePath(getClass(), "schema.sql") + EnvironmentTestUtils.addEnvironment( + this.context, + "spring.datasource.initialize:true", + "spring.datasource.schema:" + + ClassUtils.addResourcePathToPackagePath(getClass(), + "schema.sql") + "," + ClassUtils.addResourcePathToPackagePath(getClass(), "another.sql")); - this.context.getEnvironment().getPropertySources() - .addFirst(new MapPropertySource("test", map)); + this.context.register(DataSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); DataSource dataSource = this.context.getBean(DataSource.class); assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource); diff --git a/spring-boot-autoconfigure/src/test/resources/application.properties b/spring-boot-autoconfigure/src/test/resources/application.properties index a8d63792d0b..3fa3f5bae02 100644 --- a/spring-boot-autoconfigure/src/test/resources/application.properties +++ b/spring-boot-autoconfigure/src/test/resources/application.properties @@ -1 +1 @@ -foo: bucket +foo: bucket \ No newline at end of file diff --git a/spring-boot/src/main/java/org/springframework/boot/test/EnvironmentTestUtils.java b/spring-boot/src/main/java/org/springframework/boot/test/EnvironmentTestUtils.java index dda001592cb..e32ced505d5 100644 --- a/spring-boot/src/main/java/org/springframework/boot/test/EnvironmentTestUtils.java +++ b/spring-boot/src/main/java/org/springframework/boot/test/EnvironmentTestUtils.java @@ -24,6 +24,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; /** * Test utilities for setting environment values. @@ -54,7 +55,19 @@ public abstract class EnvironmentTestUtils { */ public static void addEnvironment(ConfigurableEnvironment environment, String... pairs) { - Map map = new HashMap(); + MutablePropertySources sources = environment.getPropertySources(); + Map map; + if (!sources.contains("test")) { + map = new HashMap(); + MapPropertySource source = new MapPropertySource("test", map); + sources.addFirst(source); + } + else { + @SuppressWarnings("unchecked") + Map value = (Map) sources.get("test") + .getSource(); + map = value; + } for (String pair : pairs) { int index = pair.indexOf(":"); index = index < 0 ? index = pair.indexOf("=") : index; @@ -62,7 +75,6 @@ public abstract class EnvironmentTestUtils { String value = index > 0 ? pair.substring(index + 1) : ""; map.put(key.trim(), value.trim()); } - environment.getPropertySources().addFirst(new MapPropertySource("test", map)); } }