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
This commit is contained in:
Dave Syer 2014-02-24 09:22:36 +00:00
parent 766da91137
commit 8d9c26b2df
5 changed files with 48 additions and 21 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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<String, Object> map = new HashMap<String, Object>();
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);

View File

@ -1 +1 @@
foo: bucket
foo: bucket

View File

@ -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<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) {
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));
}
}