From dbb1e222ab3ebea59d1eee8edae5334693f1047b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 26 Oct 2017 18:23:37 +0200 Subject: [PATCH] Initialize only an embedded datasource by default This commit renames spring.datasource.initialize to spring.datasource.initialization-mode and use the DataSourceInitializationMode enum. By default, only an embedded datasource is initialized. Closes gh-10773 --- ...HealthIndicatorAutoConfigurationTests.java | 2 +- .../jdbc/DataSourceInitializer.java | 40 +++++-- .../jdbc/DataSourceProperties.java | 13 ++- ...itional-spring-configuration-metadata.json | 12 ++ ...ngoRepositoriesAutoConfigurationTests.java | 14 ++- ...ingRepositoriesAutoConfigurationTests.java | 3 +- ...o4jRepositoriesAutoConfigurationTests.java | 3 +- ...stJpaDependencyAutoConfigurationTests.java | 2 +- .../DataSourceAutoConfigurationTests.java | 4 +- .../DataSourceInitializerInvokerTests.java | 31 ++--- .../jdbc/DataSourceInitializerTests.java | 110 ++++++++++++++++++ .../HikariDataSourceConfigurationTests.java | 3 +- ...iverConfigurationFailureAnalyzerTests.java | 3 +- .../JdbcTemplateAutoConfigurationTests.java | 2 +- ...tomHibernateJpaAutoConfigurationTests.java | 2 +- .../HibernateDefaultDdlAutoProviderTests.java | 2 +- .../HibernateJpaAutoConfigurationTests.java | 6 +- .../SecurityAutoConfigurationTests.java | 2 +- .../TransactionAutoConfigurationTests.java | 2 +- .../appendix-application-properties.adoc | 2 +- .../src/main/asciidoc/howto.adoc | 6 +- 21 files changed, 213 insertions(+), 51 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfigurationTests.java index dae1a9a252..63bc6f3efd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfigurationTests.java @@ -51,7 +51,7 @@ public class DataSourceHealthIndicatorAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HealthIndicatorAutoConfiguration.class, DataSourceHealthIndicatorAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialize=false"); + .withPropertyValues("spring.datasource.initialization-mode=never"); @Test public void runShouldCreateIndicator() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java index 1bc015062c..19357dc3b8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java @@ -27,6 +27,8 @@ import org.apache.commons.logging.LogFactory; import org.springframework.boot.context.config.ResourceNotFoundException; import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -90,13 +92,13 @@ class DataSourceInitializer { * @see DataSourceProperties#getSchema() */ public boolean createSchema() { - if (!this.properties.isInitialize()) { - logger.debug("Initialization disabled (not running DDL scripts)"); - return false; - } List scripts = getScripts("spring.datasource.schema", this.properties.getSchema(), "schema"); if (!scripts.isEmpty()) { + if (!isEnabled()) { + logger.debug("Initialization disabled (not running DDL scripts)"); + return false; + } String username = this.properties.getSchemaUsername(); String password = this.properties.getSchemaPassword(); runScripts(scripts, username, password); @@ -109,19 +111,41 @@ class DataSourceInitializer { * @see DataSourceProperties#getData() */ public void initSchema() { - if (!this.properties.isInitialize()) { - logger.debug("Initialization disabled (not running data scripts)"); - return; - } List scripts = getScripts("spring.datasource.data", this.properties.getData(), "data"); if (!scripts.isEmpty()) { + if (!isEnabled()) { + logger.debug("Initialization disabled (not running data scripts)"); + return; + } String username = this.properties.getDataUsername(); String password = this.properties.getDataPassword(); runScripts(scripts, username, password); } } + private boolean isEnabled() { + DataSourceInitializationMode mode = this.properties.getInitializationMode(); + if (mode == DataSourceInitializationMode.NEVER) { + return false; + } + if (mode == DataSourceInitializationMode.EMBEDDED + && !isEmbedded()) { + return false; + } + return true; + } + + private boolean isEmbedded() { + try { + return EmbeddedDatabaseConnection.isEmbedded(this.dataSource); + } + catch (Exception ex) { + logger.debug("Could not determine if datasource is embedded", ex); + return false; + } + } + private List getScripts(String propertyName, List resources, String fallback) { if (resources != null) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java index 6054c16245..800b4349ef 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java @@ -29,6 +29,7 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; import org.springframework.context.EnvironmentAware; @@ -99,9 +100,9 @@ public class DataSourceProperties private String jndiName; /** - * Populate the database using 'data.sql'. + * Initialize the datasource using available DDL and DML scripts. */ - private boolean initialize = true; + private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED; /** * Platform to use in the DDL or DML scripts (e.g. schema-${platform}.sql or @@ -376,12 +377,12 @@ public class DataSourceProperties this.jndiName = jndiName; } - public boolean isInitialize() { - return this.initialize; + public DataSourceInitializationMode getInitializationMode() { + return this.initializationMode; } - public void setInitialize(boolean initialize) { - this.initialize = initialize; + public void setInitializationMode(DataSourceInitializationMode initializationMode) { + this.initializationMode = initializationMode; } public String getPlatform() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 50d805ff76..7043cae564 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -85,6 +85,10 @@ "description": "Enable JMX support (if provided by the underlying pool).", "defaultValue": false }, + { + "name": "spring.datasource.initialization-mode", + "defaultValue": "embedded" + }, { "name": "spring.data.cassandra.compression", "defaultValue": "none" @@ -1031,6 +1035,14 @@ "level": "error" } }, + { + "name": "spring.datasource.initialize", + "defaultValue": true, + "deprecation": { + "replacement": "spring.datasource.initialization-mode", + "level": "error" + } + }, { "name": "spring.http.multipart.enabled", "type": "java.lang.Boolean", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java index 17e3f17446..3286fdb088 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java @@ -62,7 +62,8 @@ public class MixedMongoRepositoriesAutoConfigurationTests { @Test public void testDefaultRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); + TestPropertyValues.of("spring.datasource.initialization-mode:never") + .applyTo(this.context); this.context.register(TestConfiguration.class, BaseConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(CountryRepository.class)).isNotNull(); @@ -71,7 +72,8 @@ public class MixedMongoRepositoriesAutoConfigurationTests { @Test public void testMixedRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); + TestPropertyValues.of("spring.datasource.initialization-mode:never") + .applyTo(this.context); this.context.register(MixedConfiguration.class, BaseConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(CountryRepository.class)).isNotNull(); @@ -81,7 +83,8 @@ public class MixedMongoRepositoriesAutoConfigurationTests { @Test public void testJpaRepositoryConfigurationWithMongoTemplate() throws Exception { this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); + TestPropertyValues.of("spring.datasource.initialization-mode:never") + .applyTo(this.context); this.context.register(JpaConfiguration.class, BaseConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(CityRepository.class)).isNotNull(); @@ -90,7 +93,8 @@ public class MixedMongoRepositoriesAutoConfigurationTests { @Test public void testJpaRepositoryConfigurationWithMongoOverlap() throws Exception { this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); + TestPropertyValues.of("spring.datasource.initialization-mode:never") + .applyTo(this.context); this.context.register(OverlapConfiguration.class, BaseConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(CityRepository.class)).isNotNull(); @@ -101,7 +105,7 @@ public class MixedMongoRepositoriesAutoConfigurationTests { throws Exception { this.context = new AnnotationConfigApplicationContext(); TestPropertyValues - .of("spring.datasource.initialize:false", + .of("spring.datasource.initialization-mode:never", "spring.data.mongodb.repositories.enabled:false") .applyTo(this.context); this.context.register(OverlapConfiguration.class, BaseConfiguration.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveAndBlockingRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveAndBlockingRepositoriesAutoConfigurationTests.java index 73b44b42af..0ab57fb168 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveAndBlockingRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveAndBlockingRepositoriesAutoConfigurationTests.java @@ -58,7 +58,8 @@ public class MongoReactiveAndBlockingRepositoriesAutoConfigurationTests { public void shouldCreateInstancesForReactiveAndBlockingRepositories() throws Exception { this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); + TestPropertyValues.of("spring.datasource.initialization-mode:never") + .applyTo(this.context); this.context.register(BlockingAndReactiveConfiguration.class, BaseConfiguration.class); this.context.refresh(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java index a6da511cc8..3548e76db6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java @@ -93,7 +93,8 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { private void load(Class config, String... environment) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of(environment).and("spring.datasource.initialize=false") + TestPropertyValues.of(environment) + .and("spring.datasource.initialization-mode=never") .applyTo(context); context.register(config); context.register(DataSourceAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastJpaDependencyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastJpaDependencyAutoConfigurationTests.java index cfd5f58dd1..2a48446cf3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastJpaDependencyAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastJpaDependencyAutoConfigurationTests.java @@ -49,7 +49,7 @@ public class HazelcastJpaDependencyAutoConfigurationTests { HibernateJpaAutoConfiguration.class, HazelcastJpaDependencyAutoConfiguration.class)) .withPropertyValues("spring.datasource.generate-unique-name=true", - "spring.datasource.initialize=false"); + "spring.datasource.initialization-mode=never"); @Test public void registrationIfHazelcastInstanceHasRegularBeanName() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index 53c75561ed..127644b86f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -63,7 +63,7 @@ public class DataSourceAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialize=false", + .withPropertyValues("spring.datasource.initialization-mode=never", "spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt()); @@ -219,7 +219,7 @@ public class DataSourceAutoConfigurationTests { public void testDataSourceIsInitializedEarly() { this.contextRunner .withUserConfiguration(TestInitializedDataSourceConfiguration.class) - .withPropertyValues("spring.datasource.initialize=true") + .withPropertyValues("spring.datasource.initialization-mode=always") .run((context) -> assertThat(context .getBean(TestInitializedDataSourceConfiguration.class).called) .isTrue()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerInvokerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerInvokerTests.java index cd68f31b59..dbf67c2f8d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerInvokerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerInvokerTests.java @@ -59,13 +59,14 @@ public class DataSourceInitializerInvokerTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialize=false", + .withPropertyValues("spring.datasource.initialization-mode=never", "spring.datasource.url:jdbc:hsqldb:mem:init-" + UUID.randomUUID().toString()); @Test public void dataSourceInitialized() { - this.contextRunner.withPropertyValues("spring.datasource.initialize:true") + this.contextRunner + .withPropertyValues("spring.datasource.initialization-mode:always") .run((context) -> { assertThat(context).hasSingleBean(DataSource.class); DataSource dataSource = context.getBean(DataSource.class); @@ -77,7 +78,7 @@ public class DataSourceInitializerInvokerTests { @Test public void initializationAppliesToCustomDataSource() { this.contextRunner.withUserConfiguration(OneDataSource.class) - .withPropertyValues("spring.datasource.initialize:true") + .withPropertyValues("spring.datasource.initialization-mode:always") .run((context) -> { assertThat(context).hasSingleBean(DataSource.class); assertDataSourceIsInitialized(context.getBean(DataSource.class)); @@ -93,7 +94,7 @@ public class DataSourceInitializerInvokerTests { @Test public void dataSourceInitializedWithExplicitScript() { this.contextRunner - .withPropertyValues("spring.datasource.initialize:true", + .withPropertyValues("spring.datasource.initialization-mode:always", "spring.datasource.schema:" + getRelativeLocationFor("schema.sql"), "spring.datasource.data:" + getRelativeLocationFor("data.sql")) @@ -110,7 +111,8 @@ public class DataSourceInitializerInvokerTests { @Test public void dataSourceInitializedWithMultipleScripts() { this.contextRunner - .withPropertyValues("spring.datasource.initialize:true", + .withPropertyValues( + "spring.datasource.initialization-mode:always", "spring.datasource.schema:" + getRelativeLocationFor("schema.sql") + "," + getRelativeLocationFor("another.sql"), "spring.datasource.data:" + getRelativeLocationFor("data.sql")) @@ -128,7 +130,8 @@ public class DataSourceInitializerInvokerTests { @Test public void dataSourceInitializedWithExplicitSqlScriptEncoding() { - this.contextRunner.withPropertyValues("spring.datasource.initialize:true", + this.contextRunner.withPropertyValues( + "spring.datasource.initialization-mode:always", "spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.schema:" + getRelativeLocationFor("encoding-schema.sql"), @@ -155,7 +158,7 @@ public class DataSourceInitializerInvokerTests { @Test public void initializationDoesNotApplyWithSeveralDataSources() { this.contextRunner.withUserConfiguration(TwoDataSources.class) - .withPropertyValues("spring.datasource.initialize:true") + .withPropertyValues("spring.datasource.initialization-mode:always") .run((context) -> { assertThat(context.getBeanNamesForType(DataSource.class)).hasSize(2); assertDataSourceNotInitialized( @@ -190,7 +193,8 @@ public class DataSourceInitializerInvokerTests { @Test public void dataSourceInitializedWithSchemaCredentials() { - this.contextRunner.withPropertyValues("spring.datasource.initialize:true", + this.contextRunner.withPropertyValues( + "spring.datasource.initialization-mode:always", "spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.schema:" + getRelativeLocationFor("encoding-schema.sql"), @@ -205,7 +209,8 @@ public class DataSourceInitializerInvokerTests { @Test public void dataSourceInitializedWithDataCredentials() { - this.contextRunner.withPropertyValues("spring.datasource.initialize:true", + this.contextRunner.withPropertyValues( + "spring.datasource.initialization-mode:always", "spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.schema:" + getRelativeLocationFor("encoding-schema.sql"), @@ -226,10 +231,9 @@ public class DataSourceInitializerInvokerTests { new ReverseOrderResourceLoader(new DefaultResourceLoader())); return context; }).withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialize=false", + .withPropertyValues("spring.datasource.initialization-mode=always", "spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt(), - "spring.datasource.initialize:true", "spring.datasource.schema:" + getRelativeLocationFor("lexical-schema-*.sql"), "spring.datasource.data:" + getRelativeLocationFor("data.sql")) @@ -246,7 +250,7 @@ public class DataSourceInitializerInvokerTests { @Test public void testDataSourceInitializedWithInvalidSchemaResource() { this.contextRunner - .withPropertyValues("spring.datasource.initialize:true", + .withPropertyValues("spring.datasource.initialization-mode:always", "spring.datasource.schema:classpath:does/not/exist.sql") .run((context) -> { assertThat(context).hasFailed(); @@ -262,7 +266,8 @@ public class DataSourceInitializerInvokerTests { @Test public void dataSourceInitializedWithInvalidDataResource() { this.contextRunner - .withPropertyValues("spring.datasource.initialize:true", + .withPropertyValues( + "spring.datasource.initialization-mode:always", "spring.datasource.schema:" + getRelativeLocationFor("schema.sql"), "spring.datasource.data:classpath:does/not/exist.sql") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerTests.java new file mode 100644 index 0000000000..b344d967d6 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2012-2017 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.jdbc; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.UUID; + +import javax.sql.DataSource; + +import com.zaxxer.hikari.HikariDataSource; +import org.junit.Test; + +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.jdbc.core.JdbcTemplate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link DataSourceInitializer}. + * + * @author Stephane Nicoll + */ +public class DataSourceInitializerTests { + + @Test + public void initializeEmbeddedByDefault() { + try (HikariDataSource dataSource = createDataSource()) { + DataSourceInitializer initializer = new DataSourceInitializer( + dataSource, new DataSourceProperties()); + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + assertThat(initializer.createSchema()).isTrue(); + assertNumberOfRows(jdbcTemplate, 0); + initializer.initSchema(); + assertNumberOfRows(jdbcTemplate, 1); + } + } + + @Test + public void initializeWithModeAlways() { + try (HikariDataSource dataSource = createDataSource()) { + DataSourceProperties properties = new DataSourceProperties(); + properties.setInitializationMode(DataSourceInitializationMode.ALWAYS); + DataSourceInitializer initializer = new DataSourceInitializer( + dataSource, properties); + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + assertThat(initializer.createSchema()).isTrue(); + assertNumberOfRows(jdbcTemplate, 0); + initializer.initSchema(); + assertNumberOfRows(jdbcTemplate, 1); + } + } + + private void assertNumberOfRows(JdbcTemplate jdbcTemplate, int count) { + assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) from BAR", Integer.class)) + .isEqualTo(count); + } + + @Test + public void initializeWithModeNever() { + try (HikariDataSource dataSource = createDataSource()) { + DataSourceProperties properties = new DataSourceProperties(); + properties.setInitializationMode(DataSourceInitializationMode.NEVER); + DataSourceInitializer initializer = new DataSourceInitializer( + dataSource, properties); + assertThat(initializer.createSchema()).isFalse(); + } + } + + @Test + public void initializeOnlyEmbeddedByDefault() throws SQLException { + DatabaseMetaData metadata = mock(DatabaseMetaData.class); + given(metadata.getDatabaseProductName()).willReturn("MySQL"); + Connection connection = mock(Connection.class); + given(connection.getMetaData()).willReturn(metadata); + DataSource dataSource = mock(DataSource.class); + given(dataSource.getConnection()).willReturn(connection); + + DataSourceInitializer initializer = new DataSourceInitializer( + dataSource, new DataSourceProperties()); + assertThat(initializer.createSchema()).isFalse(); + verify(dataSource.getConnection()); + } + + private HikariDataSource createDataSource() { + return DataSourceBuilder.create() + .type(HikariDataSource.class) + .url("jdbc:h2:mem:" + UUID.randomUUID().toString()).build(); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java index 88415a8606..d9f8fdf532 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java @@ -103,7 +103,8 @@ public class HikariDataSourceConfigurationTests { private void load(String... environment) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - TestPropertyValues.of(environment).and("spring.datasource.initialize=false") + TestPropertyValues.of(environment) + .and("spring.datasource.initialization-mode=never") .and("spring.datasource.type=" + HikariDataSource.class.getName()) .applyTo(ctx); ctx.register(DataSourceAutoConfiguration.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDriverConfigurationFailureAnalyzerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDriverConfigurationFailureAnalyzerTests.java index 360d13cba6..12eaaf233b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDriverConfigurationFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDriverConfigurationFailureAnalyzerTests.java @@ -63,7 +63,8 @@ public class HikariDriverConfigurationFailureAnalyzerTests { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); TestPropertyValues .of("spring.datasource.type=" + HikariDataSource.class.getName(), - "spring.datasource.hikari.data-source-class-name=com.example.Foo") + "spring.datasource.hikari.data-source-class-name=com.example.Foo", + "spring.datasource.initialization-mode=always") .applyTo(context); context.register(configuration); try { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java index f0892143e5..0a931d2bfd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java @@ -158,7 +158,7 @@ public class JdbcTemplateAutoConfigurationTests { public void load(Class config, String... environment) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.datasource.initialize:false", + TestPropertyValues.of("spring.datasource.initialization-mode:never", "spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt()) .applyTo(ctx); TestPropertyValues.of(environment).applyTo(ctx); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java index 21aa11bc29..2e6797cb17 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java @@ -73,7 +73,7 @@ public class CustomHibernateJpaAutoConfigurationTests { @Test public void defaultDatabaseForH2() { this.contextRunner.withPropertyValues("spring.datasource.url:jdbc:h2:mem:testdb", - "spring.datasource.initialize:false").run((context) -> { + "spring.datasource.initialization-mode:never").run((context) -> { HibernateJpaVendorAdapter bean = context .getBean(HibernateJpaVendorAdapter.class); Database database = (Database) ReflectionTestUtils.getField(bean, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java index 90a29fbb62..65f693f427 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java @@ -42,7 +42,7 @@ public class HibernateDefaultDdlAutoProviderTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class)) - .withPropertyValues("spring.datasource.initialize:false"); + .withPropertyValues("spring.datasource.initialization-mode:never"); @Test public void defaultDdlAutoForMysql() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index 4a44badef9..b3259ce4d8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -114,7 +114,7 @@ public class HibernateJpaAutoConfigurationTests @Test public void testFlywaySwitchOffDdlAuto() { contextRunner() - .withPropertyValues("spring.datasource.initialize:false", + .withPropertyValues("spring.datasource.initialization-mode:never", "spring.flyway.locations:classpath:db/city") .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) .run((context) -> assertThat(context).hasNotFailed()); @@ -123,7 +123,7 @@ public class HibernateJpaAutoConfigurationTests @Test public void testFlywayPlusValidation() { contextRunner() - .withPropertyValues("spring.datasource.initialize:false", + .withPropertyValues("spring.datasource.initialization-mode:never", "spring.flyway.locations:classpath:db/city", "spring.jpa.hibernate.ddl-auto:validate") .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) @@ -133,7 +133,7 @@ public class HibernateJpaAutoConfigurationTests @Test public void testLiquibasePlusValidation() { contextRunner() - .withPropertyValues("spring.datasource.initialize:false", + .withPropertyValues("spring.datasource.initialization-mode:never", "spring.liquibase.changeLog:classpath:db/changelog/db.changelog-city.yaml", "spring.jpa.hibernate.ddl-auto:validate") .withConfiguration( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java index b2055e3398..b06f4709c5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java @@ -209,7 +209,7 @@ public class SecurityAutoConfigurationTests { this.context = new AnnotationConfigWebApplicationContext(); this.context.setServletContext(new MockServletContext()); TestPropertyValues.of("spring.datasource.url:jdbc:hsqldb:mem:testsecdb", - "spring.datasource.initialize:false").applyTo(this.context); + "spring.datasource.initialization-mode:never").applyTo(this.context); this.context.register(EntityConfiguration.class, PropertyPlaceholderAutoConfiguration.class, DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java index 4ba702cecb..e5932698ab 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java @@ -70,7 +70,7 @@ public class TransactionAutoConfigurationTests { public void singleTransactionManager() { load(new Class[] { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }, - "spring.datasource.initialize:false"); + "spring.datasource.initialization-mode:never"); PlatformTransactionManager transactionManager = this.context .getBean(PlatformTransactionManager.class); TransactionTemplate transactionTemplate = this.context diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 628d762a08..556a344584 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -658,7 +658,7 @@ content into your application; rather pick only the properties that you need. spring.datasource.driver-class-name= # Fully qualified name of the JDBC driver. Auto-detected based on the URL by default. spring.datasource.generate-unique-name=false # Generate a random datasource name. spring.datasource.hikari.*= # Hikari specific settings - spring.datasource.initialize=true # Populate the database using 'data.sql'. + spring.datasource.initialization-mode=embedded # Initialize the datasource using available DDL and DML scripts. spring.datasource.jmx-enabled=false # Enable JMX support (if provided by the underlying pool). spring.datasource.jndi-name= # JNDI location of the datasource. Class, url, username & password are ignored when set. spring.datasource.name=testdb # Name of the datasource. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index c8fc317a51..3da3b438e2 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1921,6 +1921,10 @@ is the value of `spring.datasource.platform`. This allows you to switch to datab specific scripts if necessary, e.g. you might choose to set it to the vendor name of the database (`hsqldb`, `h2`, `oracle`, `mysql`, `postgresql` etc.). +Spring Boot automatically creates the schema of an embedded `DataSource`. This behavior +can be customized using the `spring.datasource.initialization-mode` property (can also be +`always` or `never`). + Spring Boot enables the fail-fast feature of the Spring JDBC initializer by default, so if the scripts cause exceptions the application will fail to start. You can tune that using `spring.datasource.continue-on-error`. @@ -1929,8 +1933,6 @@ NOTE: In a JPA-based app, you can choose to let Hibernate create the schema or u `schema.sql` but not both. Make sure to disable `spring.jpa.hibernate.ddl-auto` if you chose the later. -You can also disable initialization by setting `spring.datasource.initialize` to `false`. - [[howto-initialize-a-spring-batch-database]]