声明
这个系列文章是翻译自https://www.baeldung.com/的系列博客,个人感觉是一个非常不错的Spring Boot 教程。原网站属于一个公司,主要开展有偿培训业务,但提供相关文字教程的免费阅读和下载。因为我并没有在网页找到相关版权描述信息,所以并不能确定是否可以自由翻译和转载,如果有版权问题,请联系我,我会撤下这个系列文章。
原文地址:
因为版权的关系,本文禁止转载。
概述
但有时我们需要对数据库更改进行更细粒度的控制。这就是我们可以在Spring中使用 data.sql 和 schema.sql 文件的时候。
data.sql 文件
我们还假设我们正在使用 JPA,并在我们的项目中定义一个简单的 Country 实体:
public class Country {
strategy = IDENTITY)
( private Integer id;
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文档,了解如何。
使用 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 注释来创建一个新表,并为集成测试加载初始数据:
"/employees_schema.sql", "/import_employees.sql"})
({public class SpringBootInitialLoadIntegrationTest {
private EmployeeRepository employeeRepository;
public void testLoadDataForTestClass() {
assertEquals(3, employeeRepository.findAll().size());
}
}
以下是 @Sql 注解的属性:
-
config ——SQL脚本的本地配置。我们将在下一节中详细描述这一点。
-
executionPhase ——我们还可以指定何时执行脚本,BEFORE_TEST_METHOD或AFTER_TEST_METHOD。
-
statements ——我们可以声明要执行的内联SQL语句。
-
scripts ——我们可以声明要执行的SQL脚本文件的路径。这是value属性的别名。
@Sql 注释可以在类级别或方法级别使用。
我们将通过注解该方法来加载特定测试用例所需的额外数据:
"/import_senior_employees.sql"})
({public void testLoadDataForTestCase() {
assertEquals(5, employeeRepository.findAll().size());
}
@SqlConfig
我们可以使用 @SqlConfig 注释配置解析和运行SQL脚本的方式。
@SqlConfig 可以在类级别声明,在那里它充当全局配置。或者我们可以使用它来配置特定的 @Sql 注释。
让我们看一个例子,我们指定了SQL脚本的编码以及执行脚本的事务模式:
scripts = {"/import_senior_employees.sql"},
( config = (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注解:
({ scripts = "/employees_schema.sql",
( config = (transactionMode = TransactionMode.ISOLATED)),
"/import_employees.sql")})
(public class SpringBootSqlGroupAnnotationIntegrationTest {
private EmployeeRepository employeeRepository;
public void testLoadDataForTestCase() {
assertEquals(3, employeeRepository.findAll().size());
}
}
结论
在这篇快速文章中,我们看到了如何利用schema.sql和data.sql文件来设置初始模式并使用数据填充它。
我们还研究了如何使用 @Sql 、 @SqlConfig 和@SqlGroup注解来加载测试数据进行测试。
请记住,这种方法更适合基本和简单的场景,任何高级数据库处理都需要更高级和更精细的工具,如 或。
代码片段可以
文章评论