commit
ee41dbdd8f
|
|
@ -32,8 +32,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
|
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.boot.jdbc.init.DataSourceInitializationSettings;
|
||||
import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer;
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
|
@ -148,9 +148,10 @@ class LiquibaseEndpointTests {
|
|||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseConnection.get(getClass().getClassLoader()).getType())
|
||||
.setName(UUID.randomUUID().toString()).build();
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(Arrays.asList("classpath:/db/create-custom-schema.sql"));
|
||||
ScriptDataSourceInitializer initializer = new ScriptDataSourceInitializer(dataSource, settings);
|
||||
DataSourceScriptDatabaseInitializer initializer = new DataSourceScriptDatabaseInitializer(dataSource,
|
||||
settings);
|
||||
initializer.initializeDatabase();
|
||||
return dataSource;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfi
|
|||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.DataSourceInitializationMode;
|
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.boot.jdbc.init.DataSourceInitializationSettings;
|
||||
import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer;
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
|
|
@ -56,7 +56,7 @@ import org.springframework.util.StringUtils;
|
|||
|
||||
/**
|
||||
* Configuration for {@link DataSource} initialization using a
|
||||
* {@link ScriptDataSourceInitializer} with DDL and DML scripts.
|
||||
* {@link DataSourceScriptDatabaseInitializer} with DDL and DML scripts.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
|
|
@ -87,13 +87,13 @@ class DataSourceInitializationConfiguration {
|
|||
@org.springframework.context.annotation.Conditional(DifferentCredentialsCondition.class)
|
||||
@org.springframework.context.annotation.Import(DataSourceInitializationDependencyConfigurer.class)
|
||||
@ConditionalOnSingleCandidate(DataSource.class)
|
||||
@ConditionalOnMissingBean(ScriptDataSourceInitializer.class)
|
||||
@ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class)
|
||||
static class InitializationSpecificCredentialsDataSourceInitializationConfiguration {
|
||||
|
||||
@Bean
|
||||
ScriptDataSourceInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider<DataSource> dataSource,
|
||||
DataSourceScriptDatabaseInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider<DataSource> dataSource,
|
||||
DataSourceProperties properties, ResourceLoader resourceLoader) {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(scriptLocations(properties.getSchema(), "schema", properties.getPlatform()));
|
||||
settings.setContinueOnError(properties.isContinueOnError());
|
||||
settings.setSeparator(properties.getSeparator());
|
||||
|
|
@ -106,9 +106,9 @@ class DataSourceInitializationConfiguration {
|
|||
|
||||
@Bean
|
||||
@DependsOn("ddlOnlyScriptDataSourceInitializer")
|
||||
ScriptDataSourceInitializer dmlOnlyScriptDataSourceInitializer(ObjectProvider<DataSource> dataSource,
|
||||
DataSourceScriptDatabaseInitializer dmlOnlyScriptDataSourceInitializer(ObjectProvider<DataSource> dataSource,
|
||||
DataSourceProperties properties, ResourceLoader resourceLoader) {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setDataLocations(scriptLocations(properties.getData(), "data", properties.getPlatform()));
|
||||
settings.setContinueOnError(properties.isContinueOnError());
|
||||
settings.setSeparator(properties.getSeparator());
|
||||
|
|
@ -144,13 +144,13 @@ class DataSourceInitializationConfiguration {
|
|||
@org.springframework.context.annotation.Import(DataSourceInitializationDependencyConfigurer.class)
|
||||
@org.springframework.context.annotation.Conditional(DataSourceInitializationCondition.class)
|
||||
@ConditionalOnSingleCandidate(DataSource.class)
|
||||
@ConditionalOnMissingBean(ScriptDataSourceInitializer.class)
|
||||
@ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class)
|
||||
static class SharedCredentialsDataSourceInitializationConfiguration {
|
||||
|
||||
@Bean
|
||||
ScriptDataSourceInitializer scriptDataSourceInitializer(DataSource dataSource, DataSourceProperties properties,
|
||||
ResourceLoader resourceLoader) {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DataSourceScriptDatabaseInitializer scriptDataSourceInitializer(DataSource dataSource,
|
||||
DataSourceProperties properties, ResourceLoader resourceLoader) {
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(scriptLocations(properties.getSchema(), "schema", properties.getPlatform()));
|
||||
settings.setDataLocations(scriptLocations(properties.getData(), "data", properties.getPlatform()));
|
||||
settings.setContinueOnError(properties.isContinueOnError());
|
||||
|
|
@ -188,12 +188,12 @@ class DataSourceInitializationConfiguration {
|
|||
|
||||
}
|
||||
|
||||
static class InitializationModeDataSourceScriptDatabaseInitializer extends ScriptDataSourceInitializer {
|
||||
static class InitializationModeDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer {
|
||||
|
||||
private final DataSourceInitializationMode mode;
|
||||
|
||||
InitializationModeDataSourceScriptDatabaseInitializer(DataSource dataSource,
|
||||
DataSourceInitializationSettings settings, DataSourceInitializationMode mode) {
|
||||
DatabaseInitializationSettings settings, DataSourceInitializationMode mode) {
|
||||
super(dataSource, settings);
|
||||
this.mode = mode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.sql.init;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class)
|
||||
@ConditionalOnSingleCandidate(DataSource.class)
|
||||
@Import(DataSourceInitializationDependencyConfigurer.class)
|
||||
class DataSourceInitializationConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource,
|
||||
SqlInitializationProperties initializationProperties) {
|
||||
DatabaseInitializationSettings settings = SettingsCreator.createFrom(initializationProperties);
|
||||
return new DataSourceScriptDatabaseInitializer(determineDataSource(dataSource,
|
||||
initializationProperties.getUsername(), initializationProperties.getPassword()), settings);
|
||||
}
|
||||
|
||||
private static DataSource determineDataSource(DataSource dataSource, String username, String password) {
|
||||
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
|
||||
DataSourceBuilder.derivedFrom(dataSource).username(username).password(password)
|
||||
.type(SimpleDriverDataSource.class).build();
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.sql.init;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.r2dbc.ConnectionFactoryBuilder;
|
||||
import org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration for initializing an SQL database accessed via an R2DBC
|
||||
* {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(ConnectionFactory.class)
|
||||
@ConditionalOnSingleCandidate(ConnectionFactory.class)
|
||||
class R2dbcInitializationConfiguration {
|
||||
|
||||
@Bean
|
||||
R2dbcScriptDatabaseInitializer r2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,
|
||||
SqlInitializationProperties properties) {
|
||||
DatabaseInitializationSettings settings = SettingsCreator.createFrom(properties);
|
||||
return new R2dbcScriptDatabaseInitializer(
|
||||
determineConnectionFactory(connectionFactory, properties.getUsername(), properties.getPassword()),
|
||||
settings);
|
||||
}
|
||||
|
||||
private static ConnectionFactory determineConnectionFactory(ConnectionFactory connectionFactory, String username,
|
||||
String password) {
|
||||
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
|
||||
ConnectionFactoryBuilder.derivefrom(connectionFactory).username(username).password(password).build();
|
||||
}
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.sql.init;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
|
||||
/**
|
||||
* Helpers class for creating {@link DatabaseInitializationSettings} from
|
||||
* {@link SqlInitializationProperties}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class SettingsCreator {
|
||||
|
||||
private SettingsCreator() {
|
||||
|
||||
}
|
||||
|
||||
static DatabaseInitializationSettings createFrom(SqlInitializationProperties properties) {
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(
|
||||
scriptLocations(properties.getSchemaLocations(), "schema", properties.getPlatform()));
|
||||
settings.setDataLocations(scriptLocations(properties.getDataLocations(), "data", properties.getPlatform()));
|
||||
settings.setContinueOnError(properties.isContinueOnError());
|
||||
settings.setSeparator(properties.getSeparator());
|
||||
settings.setEncoding(properties.getEncoding());
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static List<String> scriptLocations(List<String> locations, String fallback, String platform) {
|
||||
if (locations != null) {
|
||||
return locations;
|
||||
}
|
||||
List<String> fallbackLocations = new ArrayList<>();
|
||||
fallbackLocations.add("optional:classpath*:" + fallback + "-" + platform + ".sql");
|
||||
fallbackLocations.add("optional:classpath*:" + fallback + ".sql");
|
||||
return fallbackLocations;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,27 +16,16 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.sql.init;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.init.DataSourceInitializationSettings;
|
||||
import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer;
|
||||
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for initializing an SQL database.
|
||||
|
|
@ -45,49 +34,11 @@ import org.springframework.util.StringUtils;
|
|||
* @since 2.5.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(ScriptDataSourceInitializer.class)
|
||||
@ConditionalOnSingleCandidate(DataSource.class)
|
||||
@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class)
|
||||
@ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true)
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||
@AutoConfigureAfter({ R2dbcAutoConfiguration.class, DataSourceAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(SqlInitializationProperties.class)
|
||||
@Import(DataSourceInitializationDependencyConfigurer.class)
|
||||
@Import({ R2dbcInitializationConfiguration.class, DataSourceInitializationConfiguration.class })
|
||||
public class SqlInitializationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
ScriptDataSourceInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource,
|
||||
SqlInitializationProperties initializationProperties) {
|
||||
DataSourceInitializationSettings settings = createSettings(initializationProperties);
|
||||
return new ScriptDataSourceInitializer(determineDataSource(dataSource, initializationProperties.getUsername(),
|
||||
initializationProperties.getPassword()), settings);
|
||||
}
|
||||
|
||||
private static DataSourceInitializationSettings createSettings(SqlInitializationProperties properties) {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
settings.setSchemaLocations(
|
||||
scriptLocations(properties.getSchemaLocations(), "schema", properties.getPlatform()));
|
||||
settings.setDataLocations(scriptLocations(properties.getDataLocations(), "data", properties.getPlatform()));
|
||||
settings.setContinueOnError(properties.isContinueOnError());
|
||||
settings.setSeparator(properties.getSeparator());
|
||||
settings.setEncoding(properties.getEncoding());
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static List<String> scriptLocations(List<String> locations, String fallback, String platform) {
|
||||
if (locations != null) {
|
||||
return locations;
|
||||
}
|
||||
List<String> fallbackLocations = new ArrayList<>();
|
||||
fallbackLocations.add("optional:classpath*:" + fallback + "-" + platform + ".sql");
|
||||
fallbackLocations.add("optional:classpath*:" + fallback + ".sql");
|
||||
return fallbackLocations;
|
||||
}
|
||||
|
||||
private static DataSource determineDataSource(DataSource dataSource, String username, String password) {
|
||||
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
|
||||
DataSourceBuilder.derivedFrom(dataSource).username(username).password(password)
|
||||
.type(SimpleDriverDataSource.class).build();
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.jdbc.DatabaseDriver;
|
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.boot.jdbc.init.ScriptDataSourceInitializer;
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitialization;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
|
|
@ -240,14 +240,15 @@ class DataSourceAutoConfigurationTests {
|
|||
void testDataSourceIsInitializedEarly() {
|
||||
this.contextRunner.withUserConfiguration(TestInitializedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.datasource.initialization-mode=always").run((context) -> {
|
||||
assertThat(context).hasSingleBean(ScriptDataSourceInitializer.class);
|
||||
assertThat(context).hasSingleBean(DataSourceScriptDatabaseInitializer.class);
|
||||
assertThat(context.getBean(TestInitializedDataSourceConfiguration.class).called).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNoInitializationRelatedSpringDataSourcePropertiesAreConfiguredThenInitializationBacksOff() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ScriptDataSourceInitializer.class));
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(DataSourceScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
private static Function<ApplicationContextRunner, ApplicationContextRunner> hideConnectionPools() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.sql.init;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SqlInitializationAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class SqlInitializationAutoConfigurationTests {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SqlInitializationAutoConfiguration.class)).withPropertyValues(
|
||||
"spring.datasource.generate-unique-name:true", "spring.r2dbc.generate-unique-name:true");
|
||||
|
||||
@Test
|
||||
void whenNoDataSourceOrConnectionFactoryIsAvailableThenAutoConfigurationBacksOff() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConnectionFactoryIsAvailableThenR2dbcInitializerIsAutoConfigured() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(R2dbcScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConnectionFactoryIsAvailableAndInitializationIsDisabledThenInitializerIsNotAutoConfigured() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.withPropertyValues("spring.sql.init.enabled:false")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenDataSourceIsAvailableThenDataSourceInitializerIsAutoConfigured() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(DataSourceScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenDataSourceIsAvailableAndInitializationIsDisabledThenInitializerIsNotAutoConfigured() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
|
||||
.withPropertyValues("spring.sql.init.enabled:false")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenDataSourceAndConnectionFactoryAreAvailableThenOnlyR2dbcInitializerIsAutoConfigured() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.withUserConfiguration(DataSourceAutoConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class)
|
||||
.hasSingleBean(DataSource.class).hasSingleBean(R2dbcScriptDatabaseInitializer.class)
|
||||
.doesNotHaveBean(DataSourceScriptDatabaseInitializer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAnInitializerIsDefinedThenInitializerIsNotAutoConfigured() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.withUserConfiguration(DataSourceAutoConfiguration.class, DatabaseInitializerConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(AbstractScriptDatabaseInitializer.class)
|
||||
.hasBean("customInitializer"));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class DatabaseInitializerConfiguration {
|
||||
|
||||
@Bean
|
||||
AbstractScriptDatabaseInitializer customInitializer() {
|
||||
return new AbstractScriptDatabaseInitializer(new DatabaseInitializationSettings()) {
|
||||
|
||||
@Override
|
||||
protected void runScripts(List<Resource> resources, boolean continueOnError, String separator,
|
||||
Charset encoding) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1573,7 +1573,6 @@ The following example shows how to define a data source by setting properties:
|
|||
----
|
||||
|
||||
Assuming that your `FancyDataSource` has regular JavaBean properties for the URL, the username, and the pool size, these settings are bound automatically before the `DataSource` is made available to other components.
|
||||
The regular <<howto-initialize-a-database-using-spring-jdbc,database initialization>> also happens (so the relevant sub-set of `spring.datasource.*` can still be used with your custom configuration).
|
||||
|
||||
Spring Boot also provides a utility builder class, called `DataSourceBuilder`, that can be used to create one of the standard data sources (if it is on the classpath).
|
||||
The builder can detect the one to use based on what's available on the classpath.
|
||||
|
|
@ -2022,55 +2021,26 @@ It is a Hibernate feature (and has nothing to do with Spring).
|
|||
|
||||
|
||||
|
||||
[[howto-initialize-a-database-using-spring-jdbc]]
|
||||
[[howto-initialize-a-database-using-basic-scripts]]
|
||||
=== Initialize a Database using basic SQL scripts
|
||||
Spring Boot can automatically create the schema (DDL scripts) of your `DataSource` and initialize it (DML scripts).
|
||||
Spring Boot can automatically create the schema (DDL scripts) of your JDBC `DataSource` or R2DBC `ConnectionFactory` and initialize it (DML scripts).
|
||||
It loads SQL from the standard root classpath locations: `schema.sql` and `data.sql`, respectively.
|
||||
In addition, Spring Boot processes the `schema-$\{platform}.sql` and `data-$\{platform}.sql` files (if present), where `platform` is the value of configprop:spring.sql.init.platform[].
|
||||
This allows you to switch to database-specific scripts if necessary.
|
||||
For example, you might choose to set it to the vendor name of the database (`hsqldb`, `h2`, `oracle`, `mysql`, `postgresql`, and so on).
|
||||
SQL database initialization can be disabled by setting configprop:spring.sql.init.enabled[] to `false`.
|
||||
By default, Spring Boot enables the fail-fast feature of its script-based database initializer.
|
||||
This means that, if the scripts cause exceptions, the application fails to start.
|
||||
You can tune that behavior by setting configprop:spring.sql.init.continue-on-error[].
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
When only basic SQL scripts are used, Spring Boot automatically initializes the `DataSource`.
|
||||
This initialization can be disabled by setting the configprop:spring.sql.init.enabled[] property to `false`.
|
||||
|
||||
By default, script-based `DataSource` initialization is performed before any JPA `EntityManagerFactory` beans are created.
|
||||
Script-based `DataSource` initialization is performed, by default, before any JPA `EntityManagerFactory` beans are created.
|
||||
`schema.sql` can be used to create the schema for JPA-managed entities and `data.sql` can be used to populate it.
|
||||
We do not recommend using multiple data source initialization technologies.
|
||||
However, if you want script-based `DataSource` initialization to be able to build upon the schema creation performed by Hibernate, set configprop:spring.jpa.defer-datasource-initialization[] to `true`.
|
||||
While do not recommend using multiple data source initialization technologies, if you want script-based `DataSource` initialization to be able to build upon the schema creation performed by Hibernate, set configprop:spring.jpa.defer-datasource-initialization[] to `true`.
|
||||
This will defer data source initialization until after any `EntityManagerFactory` beans have been created and initialized.
|
||||
`schema.sql` can then be used to make additions to any schema creation performed by Hibernate and `data.sql` can be used to populate it.
|
||||
|
||||
If you are using a <<spring-boot-features.adoc#howto-use-a-higher-level-database-migration-tool,Higher-level Database Migration Tool>>, like Flyway or Liquibase, you should use them alone to create and initialize the schema.
|
||||
Using the basic `schema.sql` and `data.sql` scripts alongside Flyway or Liquibase is not recommended and support will be removed in a future release.
|
||||
====
|
||||
|
||||
By default, Spring Boot enables the fail-fast feature of the Spring JDBC initializer.
|
||||
This means that, if the scripts cause exceptions, the application fails to start.
|
||||
You can tune that behavior by setting configprop:spring.sql.init.continue-on-error[].
|
||||
|
||||
To take complete control over the script-based initialization of a `DataSource`, define your own `ScriptDataSourceInitializer` bean.
|
||||
Doing so will cause the auto-configuration of script-based initialization to back off.
|
||||
If you have multiple `DataSource`s in your application, you can define multiple `ScriptDataSourceInitializer` beans.
|
||||
|
||||
|
||||
|
||||
[[howto-initialize-a-database-using-r2dbc]]
|
||||
=== Initialize a Database Using R2DBC
|
||||
If you are using R2DBC, the regular `DataSource` auto-configuration backs off so none of the options described above can be used.
|
||||
|
||||
You can initialize the database on startup using SQL scripts as shown in the following example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{include-howto}/dataaccess/R2dbcDatabaseInitializationConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
Alternatively, you can configure either <<howto-execute-flyway-database-migrations-on-startup,Flyway>> or <<howto-execute-liquibase-database-migrations-on-startup,Liquibase>> to configure a `DataSource` for you for the duration of the migration.
|
||||
Both these libraries offer properties to set the `url`, `username` and `password` of the database to migrate.
|
||||
|
||||
NOTE: When choosing this option, `org.springframework:spring-jdbc` is still a required dependency.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3936,7 +3936,7 @@ TIP: You do not need to specify a driver class name, since Spring Boot obtains t
|
|||
NOTE: At least the url should be provided.
|
||||
Information specified in the URL takes precedence over individual properties, i.e. `name`, `username`, `password` and pooling options.
|
||||
|
||||
TIP: The "`How-to`" section includes a <<howto.adoc#howto-initialize-a-database-using-r2dbc, section on how to initialize a database>>.
|
||||
TIP: The "`How-to`" section includes a <<howto.adoc#howto-initialize-a-database-using-basic-scripts, section on how to initialize a database>>.
|
||||
|
||||
To customize the connections created by a `ConnectionFactory`, i.e., set specific parameters that you do not want (or cannot) configure in your central database configuration, you can use a `ConnectionFactoryOptionsBuilderCustomizer` `@Bean`.
|
||||
The following example shows how to manually override the database port while the rest of the options is taken from the application configuration:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.jdbc.init;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
|
||||
/**
|
||||
* {@link InitializingBean} that performs {@link DataSource} initialization using schema
|
||||
* (DDL) and data (DML) scripts.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public class DataSourceScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DataSourceScriptDatabaseInitializer} that will initialize the
|
||||
* given {@code DataSource} using the given settings.
|
||||
* @param dataSource data source to initialize
|
||||
* @param settings initialization settings
|
||||
*/
|
||||
public DataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) {
|
||||
super(settings);
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code DataSource} that will be initialized.
|
||||
* @return the initialization data source
|
||||
*/
|
||||
protected final DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runScripts(List<Resource> resources, boolean continueOnError, String separator, Charset encoding) {
|
||||
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
populator.setContinueOnError(continueOnError);
|
||||
populator.setSeparator(separator);
|
||||
if (encoding != null) {
|
||||
populator.setSqlScriptEncoding(encoding.name());
|
||||
}
|
||||
for (Resource resource : resources) {
|
||||
populator.addScript(resource);
|
||||
}
|
||||
DatabasePopulatorUtils.execute(populator, this.dataSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -23,15 +23,16 @@ import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDataSour
|
|||
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector;
|
||||
|
||||
/**
|
||||
* A {@link DataSourceInitializerDetector} for {@link ScriptDataSourceInitializer}.
|
||||
* A {@link DataSourceInitializerDetector} for
|
||||
* {@link DataSourceScriptDatabaseInitializer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ScriptDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
|
||||
class DataSourceScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
|
||||
|
||||
@Override
|
||||
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
|
||||
return Collections.singleton(ScriptDataSourceInitializer.class);
|
||||
return Collections.singleton(DataSourceScriptDatabaseInitializer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Support for initializaton of a JDBC {@code DataSource}.
|
||||
* Support for initializaton of an SQL database using a JDBC {@link javax.sql.DataSource
|
||||
* DataSource}.
|
||||
*/
|
||||
package org.springframework.boot.jdbc.init;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.r2dbc.init;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
|
||||
|
||||
/**
|
||||
* An {@link InitializingBean} that initializes a database represented by an R2DBC
|
||||
* {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public class R2dbcScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer {
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@code R2dbcScriptDatabaseInitializer} that will initialize the
|
||||
* database recognized by the given {@code connectionFactory} using the given
|
||||
* {@code settings}.
|
||||
* @param connectionFactory connectionFactory for the database
|
||||
* @param settings initialization settings
|
||||
*/
|
||||
public R2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,
|
||||
DatabaseInitializationSettings settings) {
|
||||
super(settings);
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runScripts(List<Resource> scripts, boolean continueOnError, String separator, Charset encoding) {
|
||||
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
populator.setContinueOnError(continueOnError);
|
||||
populator.setSeparator(separator);
|
||||
if (encoding != null) {
|
||||
populator.setSqlScriptEncoding(encoding.name());
|
||||
}
|
||||
for (Resource script : scripts) {
|
||||
populator.addScript(script);
|
||||
}
|
||||
populator.populate(this.connectionFactory).block();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for initializaton of an SQL database using an R2DBC
|
||||
* {@link io.r2dbc.spi.ConnectionFactory ConnectionFactory}.
|
||||
*/
|
||||
package org.springframework.boot.r2dbc.init;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.jdbc.init;
|
||||
package org.springframework.boot.sql.init;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
|
@ -23,54 +23,38 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* {@link InitializingBean} that performs {@link DataSource} initialization using schema
|
||||
* (DDL) and data (DML) scripts.
|
||||
* Base class for an {@link InitializingBean} that performs SQL database initialization
|
||||
* using schema (DDL) and data (DML) scripts.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public class ScriptDataSourceInitializer implements ResourceLoaderAware, InitializingBean {
|
||||
public abstract class AbstractScriptDatabaseInitializer implements ResourceLoaderAware, InitializingBean {
|
||||
|
||||
private static final String OPTIONAL_LOCATION_PREFIX = "optional:";
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
private final DataSourceInitializationSettings settings;
|
||||
private final DatabaseInitializationSettings settings;
|
||||
|
||||
private volatile ResourceLoader resourceLoader;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ScriptDataSourceInitializer} that will initialize the given
|
||||
* {@code DataSource} using the given settings.
|
||||
* @param dataSource data source to initialize
|
||||
* Creates a new {@link AbstractScriptDatabaseInitializer} that will initialize the
|
||||
* database using the given settings.
|
||||
* @param settings initialization settings
|
||||
*/
|
||||
public ScriptDataSourceInitializer(DataSource dataSource, DataSourceInitializationSettings settings) {
|
||||
this.dataSource = dataSource;
|
||||
protected AbstractScriptDatabaseInitializer(DatabaseInitializationSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code DataSource} that will be initialized.
|
||||
* @return the initialization data source
|
||||
*/
|
||||
protected final DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
|
|
@ -148,18 +132,8 @@ public class ScriptDataSourceInitializer implements ResourceLoaderAware, Initial
|
|||
this.settings.getEncoding());
|
||||
}
|
||||
|
||||
protected void runScripts(List<Resource> resources, boolean continueOnError, String separator, Charset encoding) {
|
||||
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
populator.setContinueOnError(continueOnError);
|
||||
populator.setSeparator(separator);
|
||||
if (encoding != null) {
|
||||
populator.setSqlScriptEncoding(encoding.name());
|
||||
}
|
||||
for (Resource resource : resources) {
|
||||
populator.addScript(resource);
|
||||
}
|
||||
DatabasePopulatorUtils.execute(populator, this.dataSource);
|
||||
}
|
||||
protected abstract void runScripts(List<Resource> resources, boolean continueOnError, String separator,
|
||||
Charset encoding);
|
||||
|
||||
private static class ScriptLocationResolver {
|
||||
|
||||
|
|
@ -14,20 +14,18 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.jdbc.init;
|
||||
package org.springframework.boot.sql.init;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Settings for initializing a database using a JDBC {@link DataSource}.
|
||||
* Settings for initializing an SQL database.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public class DataSourceInitializationSettings {
|
||||
public class DatabaseInitializationSettings {
|
||||
|
||||
private List<String> schemaLocations;
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for initializaton of an SQL database.
|
||||
*/
|
||||
package org.springframework.boot.sql.init;
|
||||
|
|
@ -82,7 +82,7 @@ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
|
|||
# DataSource Initializer Detectors
|
||||
org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector=\
|
||||
org.springframework.boot.flyway.FlywayDataSourceInitializerDetector,\
|
||||
org.springframework.boot.jdbc.init.ScriptDataSourceInitializerDetector,\
|
||||
org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializerDetector,\
|
||||
org.springframework.boot.liquibase.LiquibaseDataSourceInitializerDetector,\
|
||||
org.springframework.boot.orm.jpa.JpaDataSourceInitializerDetector
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.jdbc.init;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializerTests;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Tests for {@link DataSourceScriptDatabaseInitializer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class DataSourceScriptDatabaseInitializerTests extends AbstractScriptDatabaseInitializerTests {
|
||||
|
||||
private final HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class)
|
||||
.url("jdbc:h2:mem:" + UUID.randomUUID()).build();
|
||||
|
||||
@AfterEach
|
||||
void closeDataSource() {
|
||||
this.dataSource.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractScriptDatabaseInitializer createInitializer(DatabaseInitializationSettings settings) {
|
||||
return new DataSourceScriptDatabaseInitializer(this.dataSource, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int numberOfRows(String sql) {
|
||||
return new JdbcTemplate(this.dataSource).queryForObject(sql, Integer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.r2dbc.init;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.boot.r2dbc.ConnectionFactoryBuilder;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
|
||||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializerTests;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.r2dbc.core.DatabaseClient;
|
||||
|
||||
/**
|
||||
* Tests for {@link R2dbcScriptDatabaseInitializer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class R2dbcScriptDatabaseInitializerTests extends AbstractScriptDatabaseInitializerTests {
|
||||
|
||||
private final ConnectionFactory connectionFactory = ConnectionFactoryBuilder
|
||||
.withUrl("r2dbc:h2:mem:///" + UUID.randomUUID() + "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
|
||||
.build();
|
||||
|
||||
@Override
|
||||
protected AbstractScriptDatabaseInitializer createInitializer(DatabaseInitializationSettings settings) {
|
||||
return new R2dbcScriptDatabaseInitializer(this.connectionFactory, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int numberOfRows(String sql) {
|
||||
return DatabaseClient.create(this.connectionFactory).sql(sql).map((row, metadata) -> row.get(0)).first()
|
||||
.map((number) -> ((Number) number).intValue()).block();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,105 +14,88 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.jdbc.init;
|
||||
package org.springframework.boot.sql.init;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ScriptDataSourceInitializer}.
|
||||
* Base class for testing {@link AbstractScriptDatabaseInitializer} implementations.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ScriptDataSourceInitializerTests {
|
||||
|
||||
private final HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class)
|
||||
.url("jdbc:h2:mem:" + UUID.randomUUID()).build();
|
||||
|
||||
@AfterEach
|
||||
void closeDataSource() {
|
||||
this.dataSource.close();
|
||||
}
|
||||
public abstract class AbstractScriptDatabaseInitializerTests {
|
||||
|
||||
@Test
|
||||
void whenDatabaseIsInitializedThenSchemaAndDataScriptsAreApplied() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(Arrays.asList("schema.sql"));
|
||||
settings.setDataLocations(Arrays.asList("data.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThat(initializer.initializeDatabase()).isTrue();
|
||||
assertThat(numberOfRows("SELECT COUNT(*) FROM EXAMPLE")).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenContinueOnErrorIsFalseThenInitializationFailsOnError() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setDataLocations(Arrays.asList("data.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThatExceptionOfType(DataAccessException.class).isThrownBy(() -> initializer.initializeDatabase());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenContinueOnErrorIsTrueThenInitializationDoesNotFailOnError() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setContinueOnError(true);
|
||||
settings.setDataLocations(Arrays.asList("data.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThat(initializer.initializeDatabase()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNoScriptsExistAtASchemaLocationThenInitializationFails() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(Arrays.asList("does-not-exist.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThatIllegalStateException().isThrownBy(initializer::initializeDatabase)
|
||||
.withMessage("No schema scripts found at location 'does-not-exist.sql'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNoScriptsExistAtADataLocationThenInitializationFails() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setDataLocations(Arrays.asList("does-not-exist.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThatIllegalStateException().isThrownBy(initializer::initializeDatabase)
|
||||
.withMessage("No data scripts found at location 'does-not-exist.sql'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNoScriptsExistAtAnOptionalSchemaLocationThenInitializationSucceeds() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(Arrays.asList("optional:does-not-exist.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThat(initializer.initializeDatabase()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNoScriptsExistAtAnOptionalDataLocationThenInitializationSucceeds() {
|
||||
DataSourceInitializationSettings settings = new DataSourceInitializationSettings();
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setDataLocations(Arrays.asList("optional:does-not-exist.sql"));
|
||||
ScriptDataSourceInitializer initializer = createInitializer(settings);
|
||||
AbstractScriptDatabaseInitializer initializer = createInitializer(settings);
|
||||
assertThat(initializer.initializeDatabase()).isFalse();
|
||||
}
|
||||
|
||||
private ScriptDataSourceInitializer createInitializer(DataSourceInitializationSettings settings) {
|
||||
return new ScriptDataSourceInitializer(this.dataSource, settings);
|
||||
}
|
||||
protected abstract AbstractScriptDatabaseInitializer createInitializer(DatabaseInitializationSettings settings);
|
||||
|
||||
private int numberOfRows(String sql) {
|
||||
return new JdbcTemplate(this.dataSource).queryForObject(sql, Integer.class);
|
||||
}
|
||||
protected abstract int numberOfRows(String sql);
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
|
|
@ -16,15 +16,8 @@
|
|||
|
||||
package smoketest.data.r2dbc;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleR2dbcApplication {
|
||||
|
|
@ -33,13 +26,4 @@ public class SampleR2dbcApplication {
|
|||
SpringApplication.run(SampleR2dbcApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApplicationRunner initializeDatabase(ConnectionFactory connectionFactory, ResourceLoader resourceLoader) {
|
||||
return (arguments) -> {
|
||||
Resource[] scripts = new Resource[] { resourceLoader.getResource("classpath:database-init.sql") };
|
||||
new ResourceDatabasePopulator(scripts).populate(connectionFactory).block();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,2 @@
|
|||
CREATE TABLE CITY (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(30),
|
||||
state VARCHAR(30),
|
||||
country VARCHAR(30)
|
||||
);
|
||||
|
||||
INSERT INTO CITY (ID, NAME, STATE, COUNTRY) values (2000, 'Washington', 'DC', 'US');
|
||||
INSERT INTO CITY (ID, NAME, STATE, COUNTRY) values (2001, 'San Francisco', 'CA', 'US');
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE CITY (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(30),
|
||||
state VARCHAR(30),
|
||||
country VARCHAR(30)
|
||||
);
|
||||
Loading…
Reference in New Issue