对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

嵌入式数据库支持

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.spring-doc.cadn.net.cn

为何使用嵌入式数据库?

嵌入式数据库在项目开发阶段很有用,因为它具有轻量级的特点。其优点包括易于配置、启动速度快、易于测试,以及在开发过程中能够快速演变你的 SQL 语句。spring-doc.cadn.net.cn

使用Spring XML创建嵌入式数据库

如果您希望将嵌入式数据库实例作为Spring中的bean公开, ApplicationContext,可以使用embedded-database标签中的spring-jdbc命名空间:spring-doc.cadn.net.cn

<jdbc:embedded-database id="dataSource" generate-name="true">
	<jdbc:script location="classpath:schema.sql"/>
	<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>

前面的配置创建了一个嵌入式HSQL数据库,并从类路径根目录中的schema.sqltest-data.sql资源中填充SQL。此外,作为最佳实践,嵌入式数据库被赋予了一个唯一生成的名称。嵌入式数据库作为类型为javax.sql.DataSource的bean提供给Spring容器,然后可以根据需要注入到数据访问对象中。spring-doc.cadn.net.cn

以编程方式创建嵌入式数据库

EmbeddedDatabaseBuilder 类提供了一个用于以编程方式构建嵌入式数据库的流畅 API。当您需要在独立环境或独立集成测试中创建嵌入式数据库时,可以使用此功能,如下例所示:spring-doc.cadn.net.cn

EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
		.generateUniqueName(true)
		.setType(H2)
		.setScriptEncoding("UTF-8")
		.ignoreFailedDrops(true)
		.addScript("schema.sql")
		.addScripts("user_data.sql", "country_data.sql")
		.build();

// perform actions against the db (EmbeddedDatabase extends javax.sql.DataSource)

db.shutdown()
val db = EmbeddedDatabaseBuilder()
		.generateUniqueName(true)
		.setType(H2)
		.setScriptEncoding("UTF-8")
		.ignoreFailedDrops(true)
		.addScript("schema.sql")
		.addScripts("user_data.sql", "country_data.sql")
		.build()

// perform actions against the db (EmbeddedDatabase extends javax.sql.DataSource)

db.shutdown()

查看 javadoc for EmbeddedDatabaseBuilder 以获取所有支持选项的更多详细信息。spring-doc.cadn.net.cn

您也可以使用 EmbeddedDatabaseBuilder 通过使用Java配置创建嵌入式数据库,如下例所示:spring-doc.cadn.net.cn

@Configuration
public class DataSourceConfig {

	@Bean
	public DataSource dataSource() {
		return new EmbeddedDatabaseBuilder()
				.generateUniqueName(true)
				.setType(H2)
				.setScriptEncoding("UTF-8")
				.ignoreFailedDrops(true)
				.addScript("schema.sql")
				.addScripts("user_data.sql", "country_data.sql")
				.build();
	}
}
@Configuration
class DataSourceConfig {

	@Bean
	fun dataSource(): DataSource {
		return EmbeddedDatabaseBuilder()
				.generateUniqueName(true)
				.setType(H2)
				.setScriptEncoding("UTF-8")
				.ignoreFailedDrops(true)
				.addScript("schema.sql")
				.addScripts("user_data.sql", "country_data.sql")
				.build()
	}
}

选择嵌入式数据库类型

本节内容介绍如何选择Spring支持的三种嵌入式数据库之一。它包括以下主题:spring-doc.cadn.net.cn

使用HSQL

Spring 支持 HSQL 1.8.0 及以上版本。如果未明确指定类型,HSQL 是默认的嵌入式数据库。要显式指定 HSQL,请将 type 标签的 embedded-database 属性设置为 HSQL。如果您使用构建器 API,请使用 setType(EmbeddedDatabaseType) 方法并传入 EmbeddedDatabaseType.HSQLspring-doc.cadn.net.cn

使用 H2

Spring 支持 H2 数据库。要启用 H2,请将 type 标签的 embedded-database 属性设置为 H2。如果您使用构建器 API,请使用 setType(EmbeddedDatabaseType) 方法并传入 EmbeddedDatabaseType.H2spring-doc.cadn.net.cn

使用 Derby

Spring 支持 Apache Derby 10.5 及以上版本。要启用 Derby,请将 type 标签的 embedded-database 属性设置为 DERBY。如果您使用构建器 API, 请调用带有 EmbeddedDatabaseType.DERBYsetType(EmbeddedDatabaseType) 方法。spring-doc.cadn.net.cn

使用嵌入式数据库测试数据访问逻辑

嵌入式数据库为测试数据访问代码提供了一种轻量级的方法。下一个示例是一个使用嵌入式数据库的数据访问集成测试模板。在不需要跨测试类重用嵌入式数据库的情况下,使用这样的模板对于一次性任务可能很有用。然而,如果您希望在测试套件内创建一个共享的嵌入式数据库,请考虑使用Spring TestContext Framework并按照使用Spring XML创建嵌入式数据库以编程方式创建嵌入式数据库中所述,在Spring ApplicationContext中将嵌入式数据库配置为一个bean。下面的列表显示了测试模板:spring-doc.cadn.net.cn

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();
	}

}
class DataAccessIntegrationTestTemplate {

	private lateinit var db: EmbeddedDatabase

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

	@Test
	fun testDataAccess() {
		val template = JdbcTemplate(db)
		template.query( /* ... */)
	}

	@AfterEach
	fun tearDown() {
		db.shutdown()
	}
}

为嵌入式数据库生成唯一名称

开发团队在测试套件意外尝试重新创建同一数据库的额外实例时,经常会遇到嵌入式数据库的错误。如果 XML 配置文件或 @Configuration 类负责创建嵌入式数据库,并且相应的配置在同一个测试套件(即同一 JVM 进程)内的多个测试场景中被重复使用,就很容易发生这种情况 — 例如,针对嵌入式数据库的集成测试,其 ApplicationContext 配置仅在激活的 bean 定义配置文件上有所不同。spring-doc.cadn.net.cn

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

为了解决这个常见问题,Spring Framework 4.2 提供了对生成嵌入式数据库唯一名称的支持。要启用生成名称的使用,请使用以下任一选项。spring-doc.cadn.net.cn

扩展嵌入式数据库支持

你可以通过两种方式扩展Spring JDBC嵌入式数据库支持:spring-doc.cadn.net.cn

  • EmbeddedDatabaseConfigurer 实现为支持新的嵌入式数据库类型。spring-doc.cadn.net.cn

  • 实现 DataSourceFactory 以支持新的 DataSource 实现,例如用于管理嵌入式数据库连接的连接池。spring-doc.cadn.net.cn

我们鼓励您在GitHub Issues上为Spring社区贡献扩展。spring-doc.cadn.net.cn