用Spring Boot加载初始数据

x33g5p2x  于2022-09-17 转载在 Spring  
字(6.8k)|赞(0)|评价(0)|浏览(819)

在这篇文章中,我们将看看用Spring Boot加载初始数据的选项。我们将看看Spring Boot的不同选项。

用Spring Boot加载初始数据

Spring Boot使管理任何类型的数据库变化变得非常容易。如果我们不定义任何自定义配置而使用默认配置,它将在我们的包中搜索实体并创建相应的表。我们可以使用Spring中的data.sqlschema.sql文件来获得对数据库改动的更多控制。这是一个强大的功能,可以让你在不同的环境中工作。让我们通过下面的例子看看如何在启动时加载这些初始数据。

1. 初始化Spring Boot JPA实体

为了用Spring Boot加载初始数据,我们可以使用Spring Boot内置的对JPA的支持。让我们假设我们有一个雇员实体,需要在数据库中初始化模式和样本数据。

public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    private String employeeName;
    private String salary;
    private Date createdAt;
    private Date updatedAt;
}

当我们运行应用程序时,Spring Boot将为我们创建一个空表,但不会为上述定义的实体填充该表。通过将Spring Boot配置文件中的spring.jpa.hibernate.ddl-auto设置为createcreate-drop,可以为你的实体自动创建模式。如果你将ddl-auto设置为create或create-drop,Hibernate将根据你的实体的映射为其生成一个模式。你需要在你的application.properties文件中添加以下属性。

spring.jpa.hibernate.ddl-auto=create

ddl-autocreate-drop值被创建时,Hibernate会在类路径上寻找import.sql,以便初始化数据。你可以在classpath上添加import.sql文件。

INSERT INTO employee VALUES 
	('Steve', '50000', '2022-04-04 11:33:30', NULL);
	('Bill', '55000', '2022-04-05 12:33:30', NULL);
	('Mark', '30000', '2022-04-01 04:31:50', '2022-04-08 09:12:32');
	('Josh', '60000', '2022-04-03 09:22:25', '2022-04-07 12:34:54');

上述方法,包括使用JPA实体,有其自身的缺点。在import.sql文件中,每一行都应该包含一条SQL语句。为了使import.sql发挥作用,它的每一行都应该有一条语句

1.1 data.sql文件

顾名思义,我们需要在classpath上添加data.sql文件。Spring Boot将扫描classpath,并在数据库更新操作中选择该文件。以下是该文件的样子。

INSERT INTO employee (employee_name, salary, created_at, updated_at)
VALUES ('Steve', '50000', '2022-04-04 11:33:30', NULL);

INSERT INTO employee (employee_name, salary, created_at, updated_at)
VALUES ('Bill', '55000', '2022-04-05 12:33:30', NULL);

INSERT INTO employee (employee_name, salary, created_at, updated_at)
VALUES ('Mark', '30000', '2022-04-01 04:31:50', '2022-04-08 09:12:32');

INSERT INTO employee (employee_name, salary, created_at, updated_at)
VALUES ('Josh', '60000', '2022-04-03 09:22:25', '2022-04-07 12:34:54');


用Spring Boot加载初始数据

1.2. schema.sql文件

如果我们不想使用默认的模式创建机制,我们可以创建一个自定义的schema.sql文件,以便用Spring Boot加载初始数据。这个文件将被Spring Boot选中用于模式创建。

CREATE TABLE employee (
  id INTEGER NOT NULL AUTO_INCREMENT, 
  employee_name varchar(45), 
  salary varchar(45) NOT NULL, 
  created_at datetime NOT NULL, 
  updated_at datetime DEFAULT NULL, 
  PRIMARY KEY (id)
);

注意,基于脚本的初始化,也就是schema.sqldata.sql,和hibernate初始化在一起会引起一些问题。

为了禁用Hibernate的自动创建,我们可以在application.properties文件中添加以下属性。这个属性将确保基于Spring Boot脚本的初始化将直接使用schema.sqldata.sql

spring.jpa.hibernate.ddl-auto=none

通过在application.proerties中设置以下属性,我们仍然可以同时拥有Hibernate自动模式生成和基于脚本的模式创建的共轭。

spring.jpa.defer-datasource-initialization=true

因此,一旦它完成模式创建,schema.sql将被读取以获得任何额外的模式变化,data.sql将被执行以填充数据库。data.sql文件和schema.sql文件中的任何变化也会影响到实际的数据库和表。默认执行基于脚本的初始化,但这只适用于嵌入式数据库。

如果你总是想用脚本初始化数据库,在application.properties文件中添加spring.sql.init.mode=always

2. 从多个数据库供应商加载数据*

Spring Boot应用程序可以通过使用JDBC数据源创建DDL脚本模式。数据源连接工厂自动创建并初始化DML脚本。这也是作为标准classpath扫描sql文件的一部分来加载SQL,即schema.sqlanddata.sql.

2.1. data.sql

我们可以使用这个文件更新数据字段。

INSERT INTO employee (employee_name, salary, created_at, updated_at) 
VALUES ('Steve', '50000', '2022-04-04 11:33:30', NULL);

我们还可以加载schema.sql文件,如第1节所述,用Spring Boot加载初始数据。我们还可以处理schema-${platform}.sqldata-${platform}.sql(平台可以是oracle、MySQL、PostgreSQL)文件。如果需要的话,这允许在数据库特定的脚本之间进行切换。数据库初始化默认发生在嵌入式内存数据库上,尽管我们可以设置spring.sql.init模式来always初始化SQL数据库。它还默认启用了基于脚本的数据库初始化器的故障快速功能,也就是说,如果脚本抛出异常,应用程序就不能启动。

这些类型的基于脚本的数据源初始化是在创建任何EntityManagerFactory豆子之前进行的。e1d34d1管理DDL并创建模式,而data.sql管理DML并填充数据库。你也可以使用高级别数据库迁移工具,如flyway或Liquibase来创建和初始化模式。这些可以帮助你制作具有自定义名称的脚本。

3. 用Hibernate来控制数据库的创建

Hibernate提供了一个JPA特定的属性来控制数据库的创建和执行DDL生成,这个属性是spring.jpa.hibernate.ddl-auto。我们也可以使用这个属性来加载Spring Boot的初始数据。它有多个属性值,分别是*createupdatecreate-dropvalidate*和<em>none</em>。每一个都有不同的功能,以不同的方式控制数据库的创建。让我们看看它们各自是如何改变下面的DDL查询的。

*创建。Hibernate将删除所有现有的表,然后从头开始创建新的表。
*更新:它根据包括注释或XML的映射创建对象。这与现有的模式进行比较,然后根据差异用于更新模式。它不会删除任何现有的表或删除任何列,即使它们不再被需要。它只会更新现有的模式,即改变数据类型并根据需要添加任何列。

  • 创建-删除。与创建属性值类似。一旦我们完成所有的操作,它将放弃整个数据库。这对单元测试很有用。
  • validate:验证.sql文件中定义的表和列是否存在于数据库中。否则它将抛出一个异常。
  • 无。关掉任何类型的DDL生成。
    如果没有检测到模式管理器,Spring Boot将在内部把这个参数值设置为create-drop,,否则其他情况下都没有。

4. 配置数据库模式的创建

默认情况下,Spring Boot DataSource将自动用模式进行初始化。如果我们想改变或定制这种行为,用Spring Boot加载初始数据,我们可以使用spring.sql.init.mode属性。这个属性有三个值。

  • 总是。这将始终初始化数据库。
  • 嵌入式:如果使用的是嵌入式数据库,则总是初始化。如果没有指定任何其他的属性值,这个属性是默认设置的。
  • never: 永远不初始化任何类型的数据库。
    使用任何非嵌入式数据库,如MySQLPostgreSQL,如果我们想初始化其模式,就有必要将此属性设置为始终。

5. 使用@Sql 注释

@Sql注解提供了一种初始化和填充我们的测试模式的声明性方法。对于我们的集成测试,让我们创建一个新的表并使用@Sql annotation加载它的初始数据。

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootInitialLoadIntegrationTest {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Test
    public void testLoadDataForTestClass() {
        assertEquals(4, employeeRepository.findAll().size());
    }
}

让我们看看***@SQL annotation***的不同组件。

  1. config - 描述了SQL脚本的本地配置。
  2. executionPhase - 我们可以指定脚本的执行时间,可以是BEFORE_TEST_METHODAFTER_TEST_METHOD
  3. statements - 允许声明要执行的内联SQL语句。
  4. scripts - 我们可以声明要执行的SQL脚本文件的路径。
@Test
@Sql({"/import_senior_employees.sql"})
public void testLoadDataForTestCase() {
    assertEquals(5, employeeRepository.findAll().size());
}

6. 使用@SqlConfig

使用@SqlConfig注解来加载Spring Boot的初始数据,我们可以配置SQL脚本如何被解析和运行。我们可以将类级配置声明为@SqlConfig,在这里它可以作为类的全局设置。或者,我们可以用它来设置特定的@Sql注释。下面是一个例子,我们指定了我们的SQL脚本的编码,以及执行它们的交易模式。

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

blockCommentStartDelimiter-这表示用来识别SQL脚本文件中块注释的开始的分隔符。
blockCommentEndDelimiter在SQL脚本文件中,它用于显示块注释的结束。
commentPrefix-用于识别单行注释的前缀

6. 使用@SqlConfig

使用@SqlConfig注解来加载Spring Boot的初始数据,我们可以配置SQL脚本的解析和运行方式。我们可以将类级配置声明为@SqlConfig,在这里它可以作为类的全局设置。或者,我们可以用它来设置特定的@Sql注释。下面是一个例子,我们指定了我们的SQL脚本的编码,以及执行它们的交易模式。

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

blockCommentStartDelimiter-这表示用来识别SQL脚本文件中块注释的开始的分隔符。
blockCommentEndDelimiter在SQL脚本文件中,它用于显示块注释的结束。
commentPrefix-用于识别SQL脚本中单行注释的前缀。
dataSource-它将针对javax.sql.DataSource bean运行XML脚本和SQL语句。
encoding-这表示SQL脚本文件将使用的编码。默认情况下,它与平台的编码相同。
errorMode-这个模式代表在运行脚本时发生错误时将使用的errorMode
separator-这定义了用于分隔不同的单独语句的字符串。默认情况下使用"-"。
transactionManager-这定义了事务使用的PlatformTransactionManager的豆子名称。
transactionMode-在事务中执行任何脚本时使用。

7. 使用@Sqlgroup注解

在Java 8及以上版本中,支持多个注解。我们可以使用这个功能,用Spring Boot加载初始数据的@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(4, employeeRepository.findAll().size());
    }
}

小结

在这篇文章中,我们看到了如何使用不同的方法来加载Spring Boot的初始数据。我们学习了如何通过使用schema.sqldata.sql文件来设置模式并将数据填充其中。此外,我们研究了如何使用@Sql@SqlConfig@SqlGroup注释为测试加载测试数据。需要注意的是,这种方法更适合于基本和简单的场景。任何高级的数据库处理都需要更高级、更完善的工具,如Liquibase和Flyway。一如既往,你可以查看我们的GitHub repository的最新源代码。

相关文章