0
点赞
收藏
分享

微信扫一扫

spring和springboot项目启动执行sql文件

Brose 2021-09-21 阅读 78

介绍:此工具类支持spring和springboot框架,支持druid/c3p0数据库连接池,支持mysql/oracle等常见数据库sql语法
数据库连接池

        <!--druid 数据源连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.20</version>
        </dependency>
        <!--c3p0 数据源连接池-->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

前提:sql文件是有顺序的。如:必须是先创建表,再插入数据。

*.sql文件项目中的位置:

  • resources/db/mysql/*.sql
  • resources/db/oralce/*.sql

默认.sql文件都是单条正常sql语法,不是多条或非基本sql语法:
例如resources/db/mysql/userentity.sql

-- 删表语句
drop table if exists userentity;
COMMIT;

-- 用户表,如果表不存在,则创建,id自增且是主键,username不能null
CREATE TABLE IF NOT EXISTS userentity(
   id bigint not null,
   username VARCHAR(50) not null,
   age int,
   createtime DATE,
   PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
COMMIT;

insert into USERENTITY(id,username,age) values (1,'小明',18);
insert into USERENTITY(id,username,age) values (2,'小刘',20);
COMMIT;

例如resources/db/oralce/userentity.sql

drop table userentity;
COMMIT;

-- 用户表
create table userentity
(
    id NUMBER(19) not null
        primary key,
    username VARCHAR2(255 char),
    createtime TIMESTAMP(6),
    age NUMBER(19)
);
COMMIT;

-- userentity用户表数据准备
insert into USERENTITY(id,username,age) values (1,'小明',21);
insert into USERENTITY(id,username,age) values (2,'小刘',22);
COMMIT;

*.sql文件,是多条或非基本sql的语法:
例如:resources/db/oralce/userentity2.sql

-- 删除测试的表
declare
    countTab number;
begin
--===============20191203==================start
    -- 删除无用表  upper:小写字符转化成大写的函数
    select count(*) into countTab from user_tables where table_name = upper('userentity');
    if countTab = 1 then
        execute immediate 'drop table userentity';
    end if;
--===============20191203==================end
end;$$

-- 用户表
create table userentity
(
    id NUMBER(19) not null
        primary key,
    username VARCHAR2(255 char),
    createtime TIMESTAMP(6),
    age NUMBER(19)
) $$

COMMIT $$

-- userentity用户表数据准备
insert into USERENTITY(id,username,age) values (1,'小明',21) $$
insert into USERENTITY(id,username,age) values (2,'小刘',22) $$

COMMIT $$

看代码:
SpringContextGetter.java

/**
 * Date: 2019-12-03 14:19
 * Author: zhengja
 * Email: zhengja@dist.com.cn
 * Desc:
 */
@Component
public class SpringContextGetter implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

情况1:druid+mysql/oralce

描述:默认.sql文件中的sql语句没有非基本sql语法。
代码演示:

@Slf4j
@Component
public class SchemaHandler {

    @Autowired
    private DataSource datasource;

    @Autowired
    private SpringContextGetter springContextGetter;

    /**
     * 执行判断数据源连接池
     */
    public void execute() throws Exception {
        //判断是druid 连接池
        if (datasource instanceof DruidDataSource){
            DruidDataSource druidDataSource = (DruidDataSource) this.datasource;
            judgeDriver(druidDataSource.getDriverClassName());
        }
    }
    
    /**
     * 根据驱动判断是mysql/oracle的.sql文件
     * @param driverClassName 驱动名称
     */
    private void judgeDriver(String driverClassName) throws SQLException, IOException {
        if (driverClassName.equals("com.mysql.jdbc.Driver") || driverClassName.equals("com.mysql.cj.jdbc.Driver")){
            executeSqlFile("mysql");
        }
        if (driverClassName.equals("oracle.jdbc.OracleDriver") || driverClassName.equals("oracle.jdbc.driver.OracleDriver")){
            executeSqlFile("oracle");
        }
    }
    
    /**
     * 执行sql文件
     * @param dbname 位于classpath:db下的文件名称
     */
    private void executeSqlFile(String dbname) throws SQLException, IOException {

        File file =  ResourceUtils.getFile("classpath:db"+File.separator+dbname);
        if (!file.exists()){
            log.info("不存在【 "+"classpath:db"+File.separator+dbname+"】文件");
            return;
        }
        File[] files = file.listFiles();
        for (File f : files){
            String sqlRelativePath = "classpath:db"+File.separator+dbname+File.separator+f.getName();
            Resource resource = springContextGetter.getApplicationContext().getResource(sqlRelativePath);
            //一条sql语句,默认以";"结尾区分
            ScriptUtils.executeSqlScript(this.datasource.getConnection(), new EncodedResource(resource,"UTF-8"));
        }
    }
}
    

情况2:c3p0+mysql/oracle

描述:默认.sql文件中的sql语句没有非基本sql语法。
代码演示:

@Slf4j
@Component
public class SchemaHandler {

    @Autowired
    private DataSource datasource;

    @Autowired
    private SpringContextGetter springContextGetter;

    /**
     * 执行判断数据源连接池
     */
    public void execute() throws Exception {
        //判断是c3p0 连接池
        if (datasource instanceof ComboPooledDataSource){
            ComboPooledDataSource comboPooledDataSource = (ComboPooledDataSource) this.datasource;
            judgeDriver(comboPooledDataSource.getDriverClass());
        }
    }
    
    //代码和上面一样
    ......
}

情况3:druid/c3p0+oracle/mysql

描述:默认.sql文件中的sql语句没有非基本sql语法。
代码演示:

@Slf4j
@Component
public class SchemaHandler {

    @Autowired
    private DataSource datasource;

    @Autowired
    private SpringContextGetter springContextGetter;

    /**
     * 执行判断数据源连接池
     */
    public void execute() throws Exception {
        //判断是c3p0/druid 连接池
        if (datasource instanceof DruidDataSource){
            DruidDataSource druidDataSource = (DruidDataSource) this.datasource;
            judgeDriver(druidDataSource.getDriverClassName());
        }
        if (datasource instanceof ComboPooledDataSource){
            ComboPooledDataSource comboPooledDataSource = (ComboPooledDataSource) this.datasource;
            judgeDriver(comboPooledDataSource.getDriverClass());
        }
    }
    
    //代码和上面一样
    ......
}

情况4:druid/c3p0+oracle/mysql

特殊情况:比如说有非基本sql语句出现,需要将默认分割符号";"替换成"$$"。
描述: .sql文件中的sql语句有非基本sql语法。

比如:oracle的sql语句是非基本sql语法,将默认分割符号";"替换成"$$"。
位置:resources/db/oralce/orcl-0-准备数据.sql

-- 删除测试的表
declare
    countTab number;
begin
--===============20191203==================start
    -- 删除无用表  upper:小写字符转化成大写的函数
    select count(*) into countTab from user_tables where table_name = upper('userentity');
    if countTab = 1 then
        execute immediate 'drop table userentity';
    end if;
--===============20191203==================end
end;$$

-- 用户表
create table userentity
(
    id NUMBER(19) not null
        primary key,
    username VARCHAR2(255 char),
    createtime TIMESTAMP(6),
    age NUMBER(19)
) $$

COMMIT $$

-- userentity用户表数据准备
insert into USERENTITY(id,username,age) values (SEQ_MY_USER.NEXTVAL,'小明',21) $$
insert into USERENTITY(id,username,age) values (SEQ_MY_USER.NEXTVAL,'小刘',22) $$

COMMIT $$

代码演示:

@Slf4j
@Component
public class SchemaHandler {

    @Autowired
    private DataSource datasource;

    @Autowired
    private SpringContextGetter springContextGetter;

    /**
     * 执行判断数据源连接池
     */
    public void execute() throws Exception {
        //判断是c3p0/druid 连接池
        if (datasource instanceof DruidDataSource){
            DruidDataSource druidDataSource = (DruidDataSource) this.datasource;
            judgeDriver(druidDataSource.getDriverClassName());
        }
        if (datasource instanceof ComboPooledDataSource){
            ComboPooledDataSource comboPooledDataSource = (ComboPooledDataSource) this.datasource;
            judgeDriver(comboPooledDataSource.getDriverClass());
        }
    }
    
    /**
     * 根据驱动判断是mysql/oracle的.sql文件
     * @param driverClassName 驱动名称
     */
    private void judgeDriver(String driverClassName) throws SQLException, IOException {
        if (driverClassName.equals("com.mysql.jdbc.Driver") || driverClassName.equals("com.mysql.cj.jdbc.Driver")){
            executeSqlFile("mysql");
        }
        if (driverClassName.equals("oracle.jdbc.OracleDriver") || driverClassName.equals("oracle.jdbc.driver.OracleDriver")){
            executeSqlFile("oracle");
        }
    }
    
    /**
     * 执行sql文件
     * @param dbname 位于classpath:db下的文件名称
     */
    private void executeSqlFile(String dbname) throws SQLException, IOException {

        File file =  ResourceUtils.getFile("classpath:db"+File.separator+dbname);
        if (!file.exists()){
            log.info("不存在【 "+"classpath:db"+File.separator+dbname+"】文件");
            return;
        }
        File[] files = file.listFiles();
        if (dbname.equals("oracle")){
            for (File f : files){
                String sqlRelativePath = "classpath:db"+File.separator+dbname+File.separator+f.getName();
                Resource resource = springContextGetter.getApplicationContext().getResource(sqlRelativePath);
                //一条sql语句以"$$"结尾区分.执行oralce的存储过程 将'declare countCol number;'当初一条sql执行爆错,因默认以";"结尾是一条sql语句,更改成以"$$"分割作为一条sql语句
                ScriptUtils.executeSqlScript(this.datasource.getConnection(), new EncodedResource(resource,"UTF-8"), false, false, "--", "$$", "/*", "*/");
            }
        }
        if (dbname.equals("mysql")){
            for (File f : files){
                String sqlRelativePath = "classpath:db"+File.separator+dbname+File.separator+f.getName();
                Resource resource = springContextGetter.getApplicationContext().getResource(sqlRelativePath);
                //一条sql语句,默认以";"结尾区分
                ScriptUtils.executeSqlScript(this.datasource.getConnection(), new EncodedResource(resource,"UTF-8"));
            }
        }
    }
}
    

启动方式1:调用接口执行sql文件

@RestController
public class SqlController {
    
    @Autowired
    private SchemaHandler schemaHandler;
    
    @GetMapping("execute/sql")
    public Object executeSql() throws Exception {
        schemaHandler.execute();
        return "sql文件执行成功!";
    }
}

启动方式2:项目启动时执行sql文件

/**
 * Date: 2019-12-04 13:18
 * Author: zhengja
 * Email: zhengja@dist.com.cn
 * Desc:在初始化Bean时,操作数据库执行sql文件
 */
@Component
public class InitSql implements InitializingBean {

    @Value("${jdbc.isStartSql}")
    private boolean isStartSql;

    @Autowired
    private SchemaHandler schemaHandler;

    @Override
    public void afterPropertiesSet() throws Exception {
        if (isStartSql){
            this.schemaHandler.execute();
        }
    }
}

最后注意点:

举报

相关推荐

0 条评论