日常问题记录:springboot项目启动加载sql脚本

项目需要在执行单元测试前初始化数据库脚本,开始用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 对象

你可能感兴趣的:(java,springboot,spring,mysql)