Embedded Database Support

org.springframework.jdbc.datasource.embedded 包为嵌入式 Java 数据库引擎提供支持。本地提供对 HSQLH2Derby 的支持。你还可以使用可扩展的 API 来插入新的嵌入式数据库类型和 DataSource 实现。

The org.springframework.jdbc.datasource.embedded package provides support for embedded Java database engines. Support for HSQL, H2, and Derby is provided natively. You can also use an extensible API to plug in new embedded database types and DataSource implementations.

Why Use an Embedded Database?

嵌入式数据库在项目的开发阶段可能会很有用,因为它具有轻量级特性。优点包括易于配置、快速启动时间、可测试性以及在开发过程中可以快速更新 SQL。

An embedded database can be useful during the development phase of a project because of its lightweight nature. Benefits include ease of configuration, quick startup time, testability, and the ability to rapidly evolve your SQL during development.

Creating an Embedded Database

可以将嵌入式数据库实例公开为 bean,如下面的示例所示:

You can expose an embedded database instance as a bean as the following example shows:

@Bean
DataSource dataSource() {
	return new EmbeddedDatabaseBuilder()
			.generateUniqueName(true)
			.setType(EmbeddedDatabaseType.H2)
			.addScripts("schema.sql", "test-data.sql")
			.build();
}

前面的配置创建一个嵌入式 H2 数据库,该数据库使用类路径根目录中的 schema.sqltest-data.sql 资源中的 SQL 进行填充。此外,最佳实践是为嵌入式数据库分配一个唯一生成的名称。该嵌入式数据库以 javax.sql.DataSource 类型的 bean 的形式提供给 Spring 容器,然后可以根据需要注入到数据访问对象中。

The preceding configuration creates an embedded H2 database that is populated with SQL from the schema.sql and test-data.sql resources in the root of the classpath. In addition, as a best practice, the embedded database is assigned a uniquely generated name. The embedded database is made available to the Spring container as a bean of type javax.sql.DataSource that can then be injected into data access objects as needed.

请参阅 javadoc for EmbeddedDatabaseBuilder,了解所有支持选项的更多详细信息。

See the javadoc for EmbeddedDatabaseBuilder for further details on all supported options.

Selecting the Embedded Database Type

本节介绍如何选择 Spring 支持的三个嵌入式数据库之一。它包括以下主题:

This section covers how to select one of the three embedded databases that Spring supports. It includes the following topics:

Using HSQL

Spring 支持 HSQL 1.8.0 及更高版本。如果没有显式指定类型,HSQL 是默认的嵌入式数据库。要显式指定 HSQL,请将`embedded-database` 标记的 type 属性设置为 HSQL。如果使用构建器 API,请使用 EmbeddedDatabaseType.HSQL 调用`setType(EmbeddedDatabaseType)` 方法。

Spring supports HSQL 1.8.0 and above. HSQL is the default embedded database if no type is explicitly specified. To specify HSQL explicitly, set the type attribute of the embedded-database tag to HSQL. If you use the builder API, call the setType(EmbeddedDatabaseType) method with EmbeddedDatabaseType.HSQL.

Using H2

Spring 支持 H2 数据库。要启用 H2,请将`embedded-database` 标记的 type 属性设置为 H2。如果使用构建器 API,请使用 EmbeddedDatabaseType.H2 调用`setType(EmbeddedDatabaseType)` 方法。

Spring supports the H2 database. To enable H2, set the type attribute of the embedded-database tag to H2. If you use the builder API, call the setType(EmbeddedDatabaseType) method with EmbeddedDatabaseType.H2.

Using Derby

Spring 支持 Apache Derby 10.5 及更高版本。要启用 Derby,请将`embedded-database` 标记的 type 属性设置为 DERBY。如果使用构建器 API,请使用 EmbeddedDatabaseType.DERBY 调用`setType(EmbeddedDatabaseType)` 方法。

Spring supports Apache Derby 10.5 and above. To enable Derby, set the type attribute of the embedded-database tag to DERBY. If you use the builder API, call the setType(EmbeddedDatabaseType) method with EmbeddedDatabaseType.DERBY.

Customizing the Embedded Database Type

虽然每种受支持的类型都带有默认连接设置,但在必要时,可以对其进行自定义。以下示例将 H2 与自定义驱动程序一起使用:

While each supported type comes with default connection settings, it is possible to customize them if necessary. The following example uses H2 with a custom driver:

   @Configuration
   public class DataSourceConfig {

       @Bean
       public DataSource dataSource() {
           return new EmbeddedDatabaseBuilder()
                   .setDatabaseConfigurer(EmbeddedDatabaseConfigurers
                           .customizeConfigurer(H2, this::customize))
                   .addScript("schema.sql")
                   .build();
       }

       private EmbeddedDatabaseConfigurer customize(EmbeddedDatabaseConfigurer defaultConfigurer) {
           return new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
               @Override
               public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
                   super.configureConnectionProperties(properties, databaseName);
                   properties.setDriverClass(CustomDriver.class);
               }
           };
       }
}

Testing Data Access Logic with an Embedded Database

嵌入式数据库提供了一种轻量级的方法来测试数据访问代码。下一个示例是使用嵌入式数据库的数据访问集成测试模板。当嵌入式数据库不需要在测试类之间重复使用时,使用这样的模板会很有用。但是,如果你希望创建在测试套件内共享的嵌入式数据库,请考虑使用 Spring TestContext Framework 并按照 Creating an Embedded Database 中所述将嵌入式数据库配置为 Spring ApplicationContext 中的 bean。以下清单显示了测试模板:

Embedded databases provide a lightweight way to test data access code. The next example is a data access integration test template that uses an embedded database. Using such a template can be useful for one-offs when the embedded database does not need to be reused across test classes. However, if you wish to create an embedded database that is shared within a test suite, consider using the Spring TestContext Framework and configuring the embedded database as a bean in the Spring ApplicationContext as described in Creating an Embedded Database. The following listing shows the test template:

public class DataAccessIntegrationTestTemplate {

	private EmbeddedDatabase db;

	@BeforeEach
	public void setUp() {
		// creates an HSQL in-memory database populated from default scripts
		// classpath:schema.sql and classpath:data.sql
		db = new EmbeddedDatabaseBuilder()
				.generateUniqueName(true)
				.addDefaultScripts()
				.build();
	}

	@Test
	public void testDataAccess() {
		JdbcTemplate template = new JdbcTemplate(db);
		template.query( /* ... */ );
	}

	@AfterEach
	public void tearDown() {
		db.shutdown();
	}

}

Generating Unique Names for Embedded Databases

如果开发团队的测试套件不经意间尝试重新创建同一数据库的其他实例,他们通常会遇到嵌入式数据库错误。如果 XML 配置文件或 @Configuration 类负责创建嵌入式数据库,并且相应的配置随后在同一测试套件内的多个测试场景中重复使用(即在同一 JVM 进程中)的话,很容易就会发生这种情况——例如,对嵌入式数据库执行集成测试,其`ApplicationContext` 配置仅在哪些 bean 定义概要文件处于活动状态方面有所不同。

Development teams often encounter errors with embedded databases if their test suite inadvertently attempts to recreate additional instances of the same database. This can happen quite easily if an XML configuration file or @Configuration class is responsible for creating an embedded database and the corresponding configuration is then reused across multiple testing scenarios within the same test suite (that is, within the same JVM process) — for example, integration tests against embedded databases whose ApplicationContext configuration differs only with regard to which bean definition profiles are active.

此类错误的根本原因是,Spring 的 EmbeddedDatabaseFactory(由 <jdbc:embedded-database> XML 命名空间元素和 Java 配置的 EmbeddedDatabaseBuilder 在内部使用)将嵌入式数据库的名称设置为 testdb(如果未另行指定)。对于 <jdbc:embedded-database> 的情况,嵌入式数据库通常被分配一个名称,该名称等于 bean 的 id(通常类似于 dataSource)。因此,创建嵌入式数据库的后续尝试不会导致新数据库。相反,重新使用相同的 JDBC 连接 URL,而创建新嵌入式数据库的尝试实际上是指向自同一配置创建的现有嵌入式数据库。

The root cause of such errors is the fact that Spring’s EmbeddedDatabaseFactory (used internally by both the <jdbc:embedded-database> XML namespace element and the EmbeddedDatabaseBuilder for Java configuration) sets the name of the embedded database to testdb if not otherwise specified. For the case of <jdbc:embedded-database>, the embedded database is typically assigned a name equal to the bean’s id (often, something like dataSource). Thus, subsequent attempts to create an embedded database do not result in a new database. Instead, the same JDBC connection URL is reused, and attempts to create a new embedded database actually point to an existing embedded database created from the same configuration.

为了解决此常见问题,Spring Framework 4.2 提供了生成嵌入式数据库的唯一名称的支持。要启用生成名称的使用,请使用以下选项之一。

To address this common issue, Spring Framework 4.2 provides support for generating unique names for embedded databases. To enable the use of generated names, use one of the following options.

  • EmbeddedDatabaseFactory.setGenerateUniqueDatabaseName()

  • EmbeddedDatabaseBuilder.generateUniqueName()

  • <jdbc:embedded-database generate-name="true" …​ >

Extending the Embedded Database Support

可以通过两种方式扩展 Spring JDBC 嵌入式数据库支持:

You can extend Spring JDBC embedded database support in two ways:

  • 实现 EmbeddedDatabaseConfigurer,以支持新的嵌入式数据库类型。

  • Implement EmbeddedDatabaseConfigurer to support a new embedded database type.

  • 实现 DataSourceFactory,以支持新的 DataSource 实现,例如管理嵌入式数据库连接的连接池。

  • Implement DataSourceFactory to support a new DataSource implementation, such as a connection pool to manage embedded database connections.

我们鼓励您在 GitHub Issues 向 Spring 社区贡献扩展。

We encourage you to contribute extensions to the Spring community at GitHub Issues.