红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 其它
  3. 正文

Spring Boot 教程9:加载初始数据

2023年5月27日 909点热度 0人点赞 0条评论

声明

这个系列文章是翻译自https://www.baeldung.com/的系列博客,个人感觉是一个非常不错的Spring Boot 教程。原网站属于一个公司,主要开展有偿培训业务,但提供相关文字教程的免费阅读和下载。因为我并没有在网页找到相关版权描述信息,所以并不能确定是否可以自由翻译和转载,如果有版权问题,请联系我,我会撤下这个系列文章。

原文地址:Guide on Loading Initial Data with Spring Boot

因为版权的关系,本文禁止转载。


概述

Spring Boot 使管理数据库更改变得非常容易。如果我们保留默认配置,它将搜索包中的实体并自动创建相应的表。

但有时我们需要对数据库更改进行更细粒度的控制。这就是我们可以在Spring中使用 data.sql 和 schema.sql 文件的时候。

data.sql 文件

我们还假设我们正在使用 JPA,并在我们的项目中定义一个简单的 Country 实体:

@Entity
public class Country {
​
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Integer id;
    
    @Column(nullable = false)
    private String name;
​
    //...
}

如果我们运行应用程序,Spring Boot 将为我们创建一个空表,但不会填充任何内容。

一个简单的方法是创建一个名为 data.sql 的文件:

INSERT INTO country (name) VALUES ('India');
INSERT INTO country (name) VALUES ('Brazil');
INSERT INTO country (name) VALUES ('USA');
INSERT INTO country (name) VALUES ('Italy');

默认情况下,data.sql 脚本在Hibernate初始化之前执行。我们需要Hibernate在插入数据之前创建表。为了实现这一点,我们需要延迟数据源的初始化。我们将使用下面的属性来实现这一点:

spring.jpa.defer-datasource-initialization=true

当我们在 classpath 上运行包含这个文件的项目时,Spring将获取它并使用它来填充国家表。

请注意,对于任何基于脚本的初始化,即通过 data.sql 插入数据或通过 schema.sql 创建schema(我们将在接下来学习),我们需要设置以下属性:

spring.sql.init.mode=always

对于嵌入式数据库(如H2),默认情况下将其设置为始终。

schema.sql 文件

有时,我们不想依赖默认的模式创建机制。

在这种情况下,我们可以创建一个自定义的 schema.sql 文件:

create table USERS(
  ID int not null AUTO_INCREMENT,
  NAME varchar(100) not null,
  STATUS int,
  PRIMARY KEY ( ID )
);

Spring将选择这个文件并使用它来创建一个模式。

当我们在 classpath 上运行这个文件的项目时,我们可以看到,即使Users表在我们的项目中不作为实体存在,Spring仍然通过阅读这个 schema.sql 文件在我们的数据库中创建了一个Users表。

请注意,如果我们使用基于脚本的初始化,即通过 schema.sql 和 data.sql 以及Hibernate初始化,然后同时使用它们可能会导致一些问题。

为了解决这个问题,我们可以通过Hibernate完全禁用DDL命令的执行——Hibernate使用它来创建/更新表:

spring.jpa.hibernate.ddl-auto=none

这将确保只使用 schema.sql 执行基于脚本的模式生成。

如果我们仍然希望Hibernate自动模式生成与基于脚本的模式创建和数据填充结合,我们将不得不用:

spring.jpa.defer-datasource-initialization=true

这将确保在执行Hibernate模式创建之后,还会读取 schema.sql 以获取任何其他模式更改,并执行进一步的 data.sql 以填充数据库。

另外,如前一节所述,默认情况下,仅对嵌入式数据库执行基于脚本的初始化。要始终使用脚本初始化数据库,我们必须用:

spring.sql.init.mode=always

请参考官方Spring文档,了解如何使用SQL脚本初始化数据库。

使用 Hibernate 控制数据库创建

Spring提供了Hibernate用于DDL生成的JPA特定属性:spring.jpa.hibernate.ddl-auto.

标准的Hibernate属性值是create、update、create-drop、validate和none:

  • create - Hibernate首先删除现有表,然后创建新表。

  • update -将基于映射(注释或XML)创建的对象模型与现有模式进行比较,然后Hibernate根据差异更新模式。它从不删除现有的表或列,即使应用程序不再需要它们。

  • create-drop -类似于create,除了Hibernate将在所有操作完成后删除数据库;通常用于单元测试

  • validate - Hibernate只验证表和列是否存在;否则,它抛出异常。

  • none -此值有效地关闭DDL生成。

如果没有检测到schema manager,Spring Boot 内部默认此参数值为create-drop,否则所有其他情况下都是none。

我们必须仔细设置该值,或者使用其他机制之一来初始化数据库。

自定义数据库创建

默认情况下,Spring Boot 会自动创建嵌入式 DataSource 的 schema。

如果我们需要控制或定制这个行为,我们可以使用 spring.sql.init.mode 属性,此属性采用以下三个值之一:

  • always -始终初始化数据库

  • embedded -如果使用嵌入式数据库,则始终初始化。如果未指定属性值,则为默认值。

  • never -从不初始化数据库

值得注意的是,如果我们使用非嵌入式数据库,比如MySQL或PostgreSQL,并且想要初始化它的模式,我们必须将此属性设置为 always。

此属性在Spring Boot 2.5.0 中引入;如果我们使用的是Spring Boot 的早期版本,我们需要使用spring.datasource.initialization-mode。

@Sql

Spring还提供了 @Sql 注解——一种初始化和填充我们的测试模式的声明性方式。

让我们看看如何使用 @Sql 注释来创建一个新表,并为集成测试加载初始数据:

@Sql({"/employees_schema.sql", "/import_employees.sql"})
public class SpringBootInitialLoadIntegrationTest {
​
    @Autowired
    private EmployeeRepository employeeRepository;
​
    @Test
    public void testLoadDataForTestClass() {
        assertEquals(3, employeeRepository.findAll().size());
    }
}

以下是 @Sql 注解的属性:

  • config ——SQL脚本的本地配置。我们将在下一节中详细描述这一点。

  • executionPhase ——我们还可以指定何时执行脚本,BEFORE_TEST_METHOD或AFTER_TEST_METHOD。

  • statements ——我们可以声明要执行的内联SQL语句。

  • scripts ——我们可以声明要执行的SQL脚本文件的路径。这是value属性的别名。

@Sql 注释可以在类级别或方法级别使用。

我们将通过注解该方法来加载特定测试用例所需的额外数据:

@Test
@Sql({"/import_senior_employees.sql"})
public void testLoadDataForTestCase() {
    assertEquals(5, employeeRepository.findAll().size());
}

@SqlConfig

我们可以使用 @SqlConfig 注释配置解析和运行SQL脚本的方式。

@SqlConfig 可以在类级别声明,在那里它充当全局配置。或者我们可以使用它来配置特定的 @Sql 注释。

让我们看一个例子,我们指定了SQL脚本的编码以及执行脚本的事务模式:

@Test
@Sql(scripts = {"/import_senior_employees.sql"}, 
  config = @SqlConfig(encoding = "utf-8", transactionMode = TransactionMode.ISOLATED))
public void testLoadDataForTestCase() {
    assertEquals(5, employeeRepository.findAll().size());
}

让我们看看 @SqlConfig 的各种属性:

  • blockCommentStartDelimiter ——用于标识SQL脚本文件中块注释开始的分隔符

  • blockCommentEndDelimiter ——表示SQL脚本文件中块注释结束的分隔符

  • commentPrefix ——用于标识SQL脚本文件中单行注释的前缀

  • dataSource ——运行脚本和语句的javax.sql. DataSourcebean的名称

  • encoding ——SQL脚本文件的编码;默认为平台编码

  • errorMode ——运行脚本时遇到错误时使用的模式

  • separator——用于分隔各个语句的字符串;默认值为“-”

  • transactionManager ——将用于事务的PlatformTransactionManager 的bean名称

  • transactionMode ——在事务中执行脚本时将使用的模式

@SqlGroup

Java 8及更高版本允许使用重复注解。我们也可以将此功能用于 @Sql 注释。对于Java 7及以下版本,有一个容器注释—— @SqlGroup 。

使用@SqlGroup注解,我们将声明多个@Sql注解:

@SqlGroup({
  @Sql(scripts = "/employees_schema.sql", 
    config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)),
  @Sql("/import_employees.sql")})
public class SpringBootSqlGroupAnnotationIntegrationTest {
​
    @Autowired
    private EmployeeRepository employeeRepository;
​
    @Test
    public void testLoadDataForTestCase() {
        assertEquals(3, employeeRepository.findAll().size());
    }
}

结论

在这篇快速文章中,我们看到了如何利用schema.sql和data.sql文件来设置初始模式并使用数据填充它。

我们还研究了如何使用 @Sql 、 @SqlConfig 和@SqlGroup注解来加载测试数据进行测试。

请记住,这种方法更适合基本和简单的场景,任何高级数据库处理都需要更高级和更精细的工具,如 Liquibase 或Flyway。

代码片段可以在GitHub上找到。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2023年5月27日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号