首页 > 数据库 >如何在Spring Boot代码中执行sql脚本

如何在Spring Boot代码中执行sql脚本

时间:2022-09-02 21:59:31浏览次数:70  
标签:INFO ... Spring worker Boot sql Test SqlScriptsTestExecutionListener

在spring应用运行时,有一些建表语句,或则初始化数据,需要从sql脚本导入。

本文推荐以下两种方法。

假设脚本位于/resources/ddl.sql

1 使用@sql注解

该注解可用于类和方法。

@Sql(scripts = {"/ddl.sql"}, 
    config = @SqlConfig(encoding = "utf-8", 
        transactionMode = SqlConfig.TransactionMode.ISOLATED))
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Slf4j
public class RepositoryTest {
  
    @Autowired
    AppRepository appRepository;
  
    @Test
    @Order(1)
    public void insertApp(){
        appRepository.add(...)
        // ...
    }
}

注意,如果@Sql用于class,那么测试类里面的每个测试方法在运行之前都会跑一次这个脚本

@sql上的注释有说明:

@Sql is used to annotate a test class or test method to configure SQL scripts and statements to be executed against a given database during integration tests.

...

Script execution is performed by the SqlScriptsTestExecutionListener...

看见during integration tests了吧。

另外,从注释可知,脚本是被SqlScriptsTestExecutionListener执行的。打开这个类,可以看到里面有一些方法和debug级别的日志。将这个包的日志级别设为debug:

logging.level.root=info
logging.level.org.springframework.test.context.jdbc=debug

然后运行,即可看到类似下面的日志:

 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : Started RepositoryTest in 1.959 seconds (JVM running for 2.746)
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@e4927bb dataSource = '', transactionManager = '', transactionMode = ISOLATED, encoding = 'utf-8', separator = ';',...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
 INFO [    Test worker] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertApp
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@5e704109 dataSource = '', transactionManager = '', transactionMode = ISOLATED, encoding = 'utf-8', separator = ';',...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertArtifact
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@701e3274 dataSource = '', transactionManager = '', transactionMode = ISOLATED, encoding = 'utf-8', separator = ';',...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertHost
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@48ab1f96 dataSource = '', transactionManager = '', transactionMode = ISOLATED, encoding = 'utf-8', separator = ';',...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertLicense
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@67d2c696 dataSource = '', transactionManager = '', transactionMode = ISOLATED, encoding = 'utf-8', separator = ';',...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertTag
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@2473bf20 dataSource = '', transactionManager = '', transactionMode = ISOLATED, encoding = 'utf-8', separator = ';',...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertVulnerability
 INFO [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
 INFO [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
BUILD SUCCESSFUL in 7s

从日志可见,确实在每个测试用例之前执行了脚本:

Executing SQL scripts: [class path resource [ddl.sql]]

如果只需要该脚本执行一次该怎么做呢?将@Sql(....)注解放在某个@Test方法上,比如init方法,那么该脚本只会在执行init方法之前执行一次:

@Sql(scripts = {"/ddl.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
@Test
void init() {
    log.info("createTableUseAnno");
}

日志:

 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : Started RepositoryTest in 1.916 seconds (JVM running for 2.683)
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Processing [MergedSqlConfig@6367d99b dataSource = '', transactionManager = ...
DEBUG [    Test worker] .s.t.c.j.SqlScriptsTestExecutionListener : Executing SQL scripts: [class path resource [ddl.sql]]
 INFO [    Test worker] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
 INFO [    Test worker] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : createTableUseAnno
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertApp
 INFO [    Test worker] cn.whu.wy.osgov.test.RepositoryTest      : insertArtifact
...

2 使用ScriptUtils.executeSqlScript


@Autowired
DataSource dataSource;

void createTable() throws SQLException {
    Resource classPathResource = new ClassPathResource("ddl.sql");
    EncodedResource encodedResource = new EncodedResource(classPathResource, "utf-8");
    ScriptUtils.executeSqlScript(dataSource.getConnection(), encodedResource);
}

这种方式更加灵活,DataSource可以是自己创建的。

中文编码

上面两种方法都指定了utf-8编码。当表里面有中文时,不指定时会报错。

案例:有这样一个表,

CREATE TABLE app
(
    id   int                  NOT NULL AUTO_INCREMENT,
    name varchar(50)          NOT NULL,
    env  enum ('生产','测试') NOT NULL,
    PRIMARY KEY (id),
    INDEX idx_name (name)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

env字段为枚举类型,通过本文提到的两种方法建表后(未指定utf-8编码),在插入数据时报错:

> INSERT app(name, env) VALUES ('app-1', '生产');

PreparedStatementCallback; Data truncated for column 'env' at row 1; 
nested exception is java.sql.SQLException: Data truncated for column 'env' at row 1

代码

我的这个项目使用了本文提到的内容,可以参考。

Reference

  1. Guide on Loading Initial Data with Spring Boot | Baeldung
  2. java执行SQL脚本文件 - 足下之路 - 博客园 (cnblogs.com)

标签:INFO,...,Spring,worker,Boot,sql,Test,SqlScriptsTestExecutionListener
From: https://www.cnblogs.com/duanguyuan/p/16651328.html

相关文章

  • MySQL外键
    语法在创建表的时候指定外键约束CREATETABLE表名(column1datatypenull/notnull,column2datatypenull/notnull,...CONSTRAINT外键约束名F......
  • SpringMVC 06: 日期类型的变量的注入和显示
    日期处理和日期显示日期处理此时SpringMVC的项目配置和SpringMVC博客集中(指SpringMVC02)配置相同日期处理分为单个日期处理和类中全局日期处理单个日期处理:使用@Da......
  • PostgreSQL-基础2
    一、类型转换的方式CAST(expressionAStype)expression::typetypename(expression)二、生成列生成的列是始终从其他列计算的特殊列。因此,对于列,视图对于表是......
  • SQL中的排座位问题
    排座位问题的思路表:Seat+-------------+---------------------+|ColumnName|Type|+-------------+---------------------+|id |int |......
  • SQL--统计日期期间内每天的数据量,没有补0
    需求:在某些业务后台看板中,需要统计某日期范围内每天的数据量,以及总的数据量,如果某一天没有数据,则补0。分析:1、在数据库中规定日期范围内的日期可能不全,但是最后需要统计......
  • Spring Boot 面试,一个问题就干趴下了!
    最近有很多人面试,其中不乏说对SpringBoot非常熟悉的,然后当我问到一些SpringBoot核心功能和原理的时候,没人能说得上来,或者说不到点上,可以说一个问题就问趴下了!......
  • SpringMVC
    一、SpringMVC1、回顾MVC1.1、什么是MVCMVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织......
  • 将mysql数据库定时备份到另一台服务器
    导出数据到本地当MySQL运行在Docker中时dockerexec-itmysqlmysqldump-uroot-p密码数据库名>/home/数据库名.sql没有运行在Docker中时,只需要执行后半部分常规......
  • 糟糕!线上系统频繁报错,MySQL严重死锁
    目录:MySQL都有什么锁什么情况下会造成死锁常见的死锁案例1.MySQL都有什么锁MySQL有三种锁的级别:页级、表级、行级。表级锁:开销小,加锁快;不会出现......
  • Spring注解使用
    声明Bean的注解@Controller控制层@Service业务层@Repository持久化层以上三个注解都是@Component的延申,同时也是可以使用这个注解来替代以上三个注解的任意一......