写点什么

Spring Boot「07」Loading initial data 02

作者:Samson
  • 2022-10-16
    上海
  • 本文字数:2462 字

    阅读完需:约 1 分钟

Spring Boot「07」Loading initial data 02

01-import multiple sql files

通过昨天的文章 Loading initial data 我们知道,Spring Boot 框架可以很方便地通过 data.sql (Spring JDBC) 或 import.sql (Hibernate) 加载数据到数据库中。有时候,为了可维护性,需要将一个较大的 SQL Script 拆分为多个小文件,或者需要提取某个公共的数据在多个模块之间共享,那么就会存在多个 SQL Scripts。这种情况下,如何配置多个 SQL Scripts 呢?


  • Hibernate 支持从spring.jpa.properties.hibernate.hbm2ddl.import_files=a.sql,b.sql,c.sql属性中读取多个 SQL Scripts 文件;

  • (Spring Boot 2.5.0 以后)Spring JDBC 支持从spring.sql.init.data-locations=a.sql,b.sql属性中读取多个文件;提供文件名时,支持 * 作为通配符;

  • (Spring Boot 2.5.0 以前)Spring JDBC 支持从spring.datasource.data属性中读取多个文件。


继续使用昨天的工程 payroll。我们在 resources 下添加 country_japan.sql 和 country_russia.sql 文件,其中的内容分别为:


--- country_japan.sqlINSERT INTO COUNTRY (id, name) VALUES (6, 'China');--- country_russia.sqlINSERT INTO COUNTRY (id, name) VALUES (7, 'Russia');
复制代码


并在 application.properties 中添加:spring.jpa.properties.hibernate.hbm2ddl.import_files=country_japan.sql,country_russia.sql,配置 Hibernate 加载文件。


最后,运行程序,访问 H2 GUI Console,通过查询 COUNTRY 表中的内容发现,我们在 country_*.sql 中的内容被载入到数据库中了。通过应用日志,我们也能印证这一点:


o.h.t.schema.internal.SchemaCreatorImpl  : HHH000476: Executing import script 'file:/E:/00-Workspace/01-java-projects/payroll/examples/target/classes/country_japan.sql'org.hibernate.SQL                        : INSERT INTO COUNTRY (id, name) VALUES (6, 'China')o.h.t.schema.internal.SchemaCreatorImpl  : HHH000476: Executing import script 'file:/E:/00-Workspace/01-java-projects/payroll/examples/target/classes/country_russia.sql'org.hibernate.SQL                        : INSERT INTO COUNTRY (id, name) VALUES (7, 'Russia')
复制代码


[1] Spring Boot with Multiple SQL Import Files

02-initialize and populate our test schema

进行单元测试时,有时需要先加载一些初始数据,或者在单元测试之后,需要对数据库进行清理。此时,我们可以利用 Spring Boot 中提供的@Sql注解,来指定要执行的 SQL Script 和执行时机。@Sql 可以标注在测试类或某个测试方法之上,标注在类上则说明加载的数据是全局的,对所有测试用例都有效的。继续使用上节的 payroll 项目,我们来演示下如何使用@Sql注解来加载数据。首先,新建测试类 CountryRepositoryTest,并为其增加@SpringBootTest注解;其次,在 ${project.dir}/src/test/resources 中增加一个我们要执行的 SQL Script,例如,我们希望向 COUNTRY 表中增加一条记录(8, "Japan")。


---country_japan.sqlINSERT INTO COUNTRY (id, name) VALUES (8, 'Japan');
复制代码


然后,在测试类上增加@Sql({"/country_japan.sql""})来加载数据。最后,编写方法来测试我们是否成功加载了该数据。


@SpringBootTest@Sql({"/country_japan.sql"})public class CountryRepositoryTest {    @Test    public void sqlAnnotationWorks() {        assertThat(repository.findById(8).isPresent()).isTrue();        assertThat(repository.findById(8).get().getName().equalsIgnoreCase("Japan")).isTrue();    }}
复制代码


运行后,发现测试用例通过,说明 SQL Script country_japan.sql 成功执行。


@Sql注解包含了一个属性executionPhase,它的取值可以是:BEFORE_TEST_METHOD 或 AFTER_TEST_METHOD,意为 values / scripts 指定的 SQL Scripts 何时会被运行,是在测试方法之前,还是测试方法之后。


Spring Boot 还提供了另外一个注解@SqlConfig用来控制@Sql的行为,@SqlConfig可以标注在测试类上,也可以标注在某个@Sql注解上。@SqlConfig 中可配置项包括:


  • 注释格式,多行注释,默认以/*开始,以*/结束,可以通过 blockCommentStartDelimiter 和 blockCommentEndDelimiter 修改;单行注释,默认以--开始,可以通过 commentPrefix 修改;

  • 数据源,通过 dataSource 指定,其值为 Bean 的名称;

  • 编码,通过 encoding 指定;

  • 遇到错误时的动作,通过 errorMode 指定,可选值为:DEFAULT|FAIL_ON_ERROR|CONTINUE_ON_ERROR|IGNORE_FAILED_DROPS

  • 语句间的分隔符,默认为;

  • 事务相关,事务管理器和事务模式,可分别通过 transactionManager 和 transactionMode 指定。


Java 8 以后,注解可以重复标注,例如:


@Sql({"/country_japan.sql"})@Sql({"/country_canada.sql"})public class CountryRepositoryTest {    @Test    public void sqlAnnotationWorks() {        assertThat(repository.findById(8).isPresent()).isTrue();        assertThat(repository.findById(8).get().getName().equalsIgnoreCase("Japan")).isTrue();                assertThat(repository.findById(9).isPresent()).isTrue();        assertThat(repository.findById(9).get().getName().equalsIgnoreCase("Canada")).isTrue();    }}
复制代码


但 Java 7 及之前版本是不支持上述语法的。所以 Spring Boot 提供了@SqlGroup注解,将多个@Sql注解合并在一起。下述写法等价于上述写法:


@SqlGroup({        @Sql({"/country_japan.sql"}),        @Sql({"/country_canada.sql"})})public class CountryRepositoryTest {    // ... ignored}
复制代码


[1] Quick Guide on Loading Initial Data with Spring Boot

03-总结

今天我们学习了另外两部分与加载初始化数据相关的内容。其一,Spring Boot 中如何通过 Spring JDBC 和 Hibernate 加载多个 SQL Scripts 中的数据到数据库中。其二,单元测试时如何加载数据到我们的 test schema。特别是第二部分内容,在复杂的单元测试场景中应用范围较广,是一个比较值得掌握的技能。

发布于: 刚刚阅读数: 5
用户头像

Samson

关注

还未添加个人签名 2019-07-22 加入

InfoQ签约作者 | 阿里云社区签约作者

评论

发布
暂无评论
Spring Boot「07」Loading initial data 02_Java_Samson_InfoQ写作社区