项目需要在执行单元测试前初始化数据库脚本,开始用flyway做全局脚本加载,由于是web项目,单元测试前需要先加载完spring容器的上下文,项目本身有一些数据库访问要在bean初始化时执行,在一个空数据库里就会导致项目启动阶段就失败了。
遂考虑在springboot启动该阶段加载数据库初始化的脚本。
springboot 2.X版本
在项目启动时想要加载数据库脚本以后的版本需要如下配置
schema:
# 指定的数据库脚本位置
- classpath:junitDB/schema.sql
## 数据初始化,默认加载data.sql,还会加载data-${platform}.sql文件
# #指定 DQL(数据查询)脚本或DML(数据操作)脚本 文件, 一般都是数据插入脚本文件
# platform:
# data:
# 总是执行
initialization-mode: always
详见
https://blog.csdn.net/m0_46157986/article/details/105934343
经测试,直接在yml配置文件中配置的方式,如果项目使用了自定义数据源,即排除了数据源自动装配
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 则该配置不会生效,
在测试第二种方式注入 DataSourceInitializer
@Value("classpath:junitDB/schema.sql")
private Resource sqlScriptSchema;
/**
* 是否初始化单元测试数据库,默认关闭
*/
@Value("${user.junit.initDB:false}")
private Boolean isInItDB;
@Bean
/**只在单元测试配置下装载*/
@Profile({"junit"})
/**
* 因为项目使用druid连接池并自定义了数据源,容器初始化bean完成后加载,导致init执行时机不对,无法在空库时先初始化数据库
* 所以指定DynamicDataSource装载顺序在DataSourceInitializer之后
*/
public DataSourceInitializer dataSourceInitializer( DataSource dataSource){
//是否执行初始化脚本开关
if(isInItDB)
{
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(dataSource);
dataSourceInitializer.setDatabasePopulator(databasePopulator());
return dataSourceInitializer;
}
return null;
}
private DatabasePopulator databasePopulator(){
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(sqlScriptSchema);
// populator.addScript(sqlScriptData);
// populator.addScript(sqlScriptProcedure);
// populator.addScript(sqlScriptFunction);
// populator.setSeparator("$$$"); // 分隔符,默认为;
return populator;
}
经测试,sql脚本可以执行,但仍会等到spring容器bean都加载完后才会执行,我们项目用的时druid多数据源配置,遂增加
@DependsOn(“dataSourceInitializer”)配置在从数据源上,让主数据源加载后,从数据源加载前必须先加载dataSourceInitializer
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource)
{
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
return new DynamicDataSource(masterDataSource, targetDataSources);
}
经测试达到预期,但是一旦使用其他环境启动就会因为DataSourceInitializer 配置的@Profile({“junit”})注解,只会在junit配置下启动,导致其他环境DataSourceInitializer 没有被装配导致报错
遂增加开关参数 private Boolean isInItDB; 并删除@Profile({“junit”})注解,使用isInItDB来控制注入的DataSourceInitializer 对象