Switch default to fail on error in SQL initialization

User can switch the behaviour on and off with
spring.datasource.continueOnError:true|false. I decided
not to add an extra nested level of property resolution
because of the existing spring.datasource.schema
(and other properties relating to initialization) because
concision seemed like a good thing with those more common
settings.

Fixes gh-374
pull/382/merge
Dave Syer 11 years ago
parent 766da91137
commit 8d9c26b2df

@ -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 `schema.sql` and `data.sql` (in the root of the classpath). In
addition Spring Boot will load a file `schema-${platform}.sql` where addition Spring Boot will load a file `schema-${platform}.sql` where
`platform` is the vendor name of the database (`hsqldb`, `h2, `platform` is the vendor name of the database (`hsqldb`, `h2,
`oracle`, `mysql`, `postgresql` etc.). Spring Boot *disables* the `oracle`, `mysql`, `postgresql` etc.). Spring Boot enables the
failfast feature of the Spring JDBC initializer, so if the scripts failfast feature of the Spring JDBC initializer by default, so if
cause exceptions they will be logged, but the application will still the scripts cause exceptions the application will fail.
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 To disable the failfast you can set
fail for instance), but it does mean that you need to test the state `spring.datasource.continueOnError=true`. This can be useful once an
of your database on startup if you want to be sure that it was application has matured and been deployed a few times, since the
successful (or else monitor the Spring JDBC DEBUG logs). 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 ### Higher Level Migration Tools

@ -106,13 +106,15 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
.getResources(schemaLocation))); .getResources(schemaLocation)));
} }
boolean continueOnError = this.environment.getProperty("continueOnError",
Boolean.class, false);
boolean exists = false; boolean exists = false;
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
for (Resource resource : resources) { for (Resource resource : resources) {
if (resource.exists()) { if (resource.exists()) {
exists = true; exists = true;
populator.addScript(resource); populator.addScript(resource);
populator.setContinueOnError(true); populator.setContinueOnError(continueOnError);
} }
} }

@ -24,11 +24,13 @@ import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Random;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
@ -56,6 +58,13 @@ public class DataSourceAutoConfigurationTests {
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 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 @Test
public void testDefaultDataSourceExists() throws Exception { public void testDefaultDataSourceExists() throws Exception {
this.context.register(DataSourceAutoConfiguration.class, this.context.register(DataSourceAutoConfiguration.class,
@ -85,8 +94,7 @@ public class DataSourceAutoConfigurationTests {
.addEnvironment( .addEnvironment(
this.context, this.context,
"spring.datasource.driverClassName:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfigurationTests$DatabaseDriver", "spring.datasource.driverClassName:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfigurationTests$DatabaseDriver",
"spring.datasource.url:jdbc:foo://localhost", "spring.datasource.url:jdbc:foo://localhost");
"spring.datasource.initialize:false");
this.context.register(DataSourceAutoConfiguration.class, this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
@ -141,6 +149,8 @@ public class DataSourceAutoConfigurationTests {
@Test @Test
public void testDataSourceInitialized() throws Exception { public void testDataSourceInitialized() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:true");
this.context.register(DataSourceAutoConfiguration.class, this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
@ -172,16 +182,17 @@ public class DataSourceAutoConfigurationTests {
@Test @Test
public void testDataSourceInitializedWithMultipleScripts() throws Exception { public void testDataSourceInitializedWithMultipleScripts() throws Exception {
this.context.register(DataSourceAutoConfiguration.class, EnvironmentTestUtils.addEnvironment(
PropertyPlaceholderAutoConfiguration.class); this.context,
Map<String, Object> map = new HashMap<String, Object>(); "spring.datasource.initialize:true",
map.put(DataSourceAutoConfiguration.CONFIGURATION_PREFIX + ".schema", "spring.datasource.schema:"
ClassUtils.addResourcePathToPackagePath(getClass(), "schema.sql") + ClassUtils.addResourcePathToPackagePath(getClass(),
"schema.sql")
+ "," + ","
+ ClassUtils.addResourcePathToPackagePath(getClass(), + ClassUtils.addResourcePathToPackagePath(getClass(),
"another.sql")); "another.sql"));
this.context.getEnvironment().getPropertySources() this.context.register(DataSourceAutoConfiguration.class,
.addFirst(new MapPropertySource("test", map)); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class); DataSource dataSource = this.context.getBean(DataSource.class);
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource); assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);

@ -24,6 +24,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
/** /**
* Test utilities for setting environment values. * Test utilities for setting environment values.
@ -54,7 +55,19 @@ public abstract class EnvironmentTestUtils {
*/ */
public static void addEnvironment(ConfigurableEnvironment environment, public static void addEnvironment(ConfigurableEnvironment environment,
String... pairs) { String... pairs) {
Map<String, Object> map = new HashMap<String, Object>(); MutablePropertySources sources = environment.getPropertySources();
Map<String, Object> map;
if (!sources.contains("test")) {
map = new HashMap<String, Object>();
MapPropertySource source = new MapPropertySource("test", map);
sources.addFirst(source);
}
else {
@SuppressWarnings("unchecked")
Map<String, Object> value = (Map<String, Object>) sources.get("test")
.getSource();
map = value;
}
for (String pair : pairs) { for (String pair : pairs) {
int index = pair.indexOf(":"); int index = pair.indexOf(":");
index = index < 0 ? index = pair.indexOf("=") : index; index = index < 0 ? index = pair.indexOf("=") : index;
@ -62,7 +75,6 @@ public abstract class EnvironmentTestUtils {
String value = index > 0 ? pair.substring(index + 1) : ""; String value = index > 0 ? pair.substring(index + 1) : "";
map.put(key.trim(), value.trim()); map.put(key.trim(), value.trim());
} }
environment.getPropertySources().addFirst(new MapPropertySource("test", map));
} }
} }

Loading…
Cancel
Save