springboot学习(六十二) springboot中服务启动时执行SQL脚本

文章目录

  • 前言
  • 一、方式1
  • 二、方式2

前言

有些情况下我们需要在服务启动时执行一段SQL脚本,比如建立数据库,插入一些用户角色数据等,下面介绍两种方式。

一、方式1

方式1很简单,这种方式需要使用spring的数据源自动配置。
在yaml文件或properties文件中直接配置,以properties为例:

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/newframe
spring.datasource.schema=classpath:sql/newframe.sql,classpath:sql/demo.sql
spring.datasource.initialization-mode=always

注意使用springboot2.x必须加上spring.datasource.initialization-mode=always,如果只初始化一次就够了,记得初始化后将always修改为never

将要初始化的脚本放在resources下的sql文件夹中
springboot学习(六十二) springboot中服务启动时执行SQL脚本_第1张图片

二、方式2

重点介绍下方式2,在某些情况下,未使用springboot的数据源自动配置,有没有办法初始化执行脚本呢?这里介绍使用Mybatis的ScriptRunner初始化的方式。

  1. 在配置文件中配置脚本路径和是否开启
......
#初始化脚本(多个以逗号分隔)
spring.datasource.druid.mysql1.schema=classpath:sql/newframe.sql
#是否开启脚本初始化,always-开启  never-不开启
spring.datasource.druid.mysql1.initialization-mode=never
......
  1. 在datasource初始化后根据配置的信息运行初始化脚本
 @Bean(name = "dynamicDatasource")
    public DataSource dynamicDataSource() throws SQLException {
        String db = environment.getProperty("spring.datasource.names");

        Map<Object, Object> targetDataSources = new LinkedHashMap<>(2 << 2);
        Map<String, Object> enableAtomikosMap = context.getBeansWithAnnotation(EnableAtomikos.class);
        if (db != null) {
            List<String> dbNames = Arrays.asList(db.split(","));
            if (CollectionUtil.isNotEmpty(dbNames)) {
                for (String dbName : dbNames) {
                    //初始化数据源
                    //update by zqw 20210520 添加Atomikos支持
                    DruidDataSource dataSource = initOneDatasource(dbName);
                    if (dataSource != null) {
                        if (MapUtil.isNotEmpty(enableAtomikosMap)) {
                            //如果开启了Atomikos
                            AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
                            atomikosDataSourceBean.setXaDataSource((XADataSource) dataSource);
                            //必须设置uniqueResourceName
                            atomikosDataSourceBean.setUniqueResourceName(dbName);
                            targetDataSources.put(dbName, atomikosDataSourceBean);
                        } else {
                            //如果没开启Atomikos
                            targetDataSources.put(dbName, dataSource);
                        }
                    }
                    //运行初始化脚本 add by zqw 2021-12-26
                    String path = basePath + dbName + ".";
                    String value = environment.getProperty(path + "initialization-mode");
                    if (Objects.equals("always", value)) {
                        value = environment.getProperty(path + "schema");
                        if (StringUtils.isNotEmpty(value)) {
                            runSchema(dataSource, value, dbName);
                        }
                    }

                }
            }
        }

        //如果有shardingjdbc的配置,读取
        Map<String, Object> enableShardingJdbcMap = context.getBeansWithAnnotation(EnableShardingJdbc.class);
        if (CollectionUtil.isNotEmpty(enableShardingJdbcMap)) {
            IShardingJdbcHandler shardingJdbcHandler = context.getBean(IShardingJdbcHandler.class);
            if (shardingJdbcHandler != null) {
                targetDataSources.putAll(shardingJdbcHandler.initShardingDatasource());
            }
//            DataSource dataSource = getShardingDatasource();
//            targetDataSources.put("ds0_ds1", dataSource);
        }

        DynamicDataSource dynamicDataSource = new DynamicDataSource();

        //设置数据源
        if (targetDataSources.size() > 0) {
            dynamicDataSource.setTargetDataSources(targetDataSources);
            dynamicDataSource.setDefaultTargetDataSource(targetDataSources.entrySet().iterator().next().getValue());
        } else {
            log.error("没有数据源,无法使用数据库!!!");
            return null;
        }
        dynamicDataSource.afterPropertiesSet();
        return dynamicDataSource;
    }

其他的都可以忽略,只需要关注一下带有注释2021-12-26下面的一段代码即可,意思是根据配置文件中的配置调用初始化脚本。runSchema(dataSource, value, dbName)的代码如下:

    private static void runSchema(DataSource datasource, String schemas, String dbName) {
        InputStream is = null;
        try (Connection conn = datasource.getConnection()) {
            ScriptRunner scriptRunner = new ScriptRunner(conn);
            scriptRunner.setStopOnError(false);
            for (String schemaPath : schemas.split(StrConstantEnum.COMMA.getValue())) {
                schemaPath = schemaPath.trim();
                if (schemaPath.startsWith(CommonConstant.CLASSPATH)) {
                    ClassPathResource classPathResource = new ClassPathResource(StringUtils.substringAfter(schemaPath, CommonConstant.CLASSPATH));
                    is = classPathResource.getInputStream();
                } else {
                    is = new FileInputStream(schemaPath);
                }
                try (InputStreamReader isr = new InputStreamReader(is)) {
                    scriptRunner.runScript(isr);
                }
            }
        } catch (SQLException | IOException e) {
            log.warn(MessageFormat.format("数据源:{0}运行初始化脚本失败", dbName), e);
        }
    }

主要使用了Mybatis的执行脚本功能,在初始化datasource后获取一个connection,读取某个位置存储的一段SQL脚本并执行。这样在不使用DataSourceAutoConfiguration或其他datasource自动配置方式的情况下,也能实现类似schema脚本的功能啦。

你可能感兴趣的:(spring,boot,mybatis,sql,spring,boot,java,mybatis,ScriptRunner)