此版本仍在开发中,尚未稳定。如需最新的稳定版本,请使用 Spring Framework 7.0.6spring-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

创建嵌入式数据库

您可以将嵌入式数据库实例作为bean暴露,如下例所示:spring-doc.cadn.net.cn

@Bean
DataSource dataSource() {
	return new EmbeddedDatabaseBuilder()
			.generateUniqueName(true)
			.setType(EmbeddedDatabaseType.H2)
			.addScripts("schema.sql", "test-data.sql")
			.build();
}
@Bean
fun dataSource() = EmbeddedDatabaseBuilder()
	.generateUniqueName(true)
	.setType(EmbeddedDatabaseType.H2)
	.addScripts("schema.sql", "test-data.sql")
	.build()
<jdbc:embedded-database id="dataSource" generate-name="true" type="H2">
	<jdbc:script location="classpath:schema.sql"/>
	<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>

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

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

选择嵌入式数据库类型

本节内容介绍如何选择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

自定义嵌入式数据库类型

尽管每种受支持的类型都带有默认的连接设置,但如果需要,也可以自定义这些设置。以下示例使用了带有自定义驱动程序的 H2:spring-doc.cadn.net.cn

@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);
			}
		};
	}
}
@Configuration
class DataSourceConfig {

	@Bean
	fun dataSource(): DataSource {
		return EmbeddedDatabaseBuilder()
			.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
				.customizeConfigurer(EmbeddedDatabaseType.H2) { this.customize(it) })
			.addScript("schema.sql")
			.build()
	}

	private fun customize(defaultConfigurer: EmbeddedDatabaseConfigurer): EmbeddedDatabaseConfigurer {
		return object : EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
			override fun configureConnectionProperties(
				properties: ConnectionProperties,
				databaseName: String
			) {
				super.configureConnectionProperties(properties, databaseName)
				properties.setDriverClass(CustomDriver::class.java)
			}
		}
	}
}

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

嵌入式数据库为测试数据访问代码提供了一种轻量级的方法。下一个示例是一个使用嵌入式数据库的数据访问集成测试模板。使用这样的模板在一次性情况下很有用,当嵌入式数据库不需要在测试类之间重用时。但是,如果您希望创建一个在测试套件中共享的嵌入式数据库,请考虑使用Spring测试上下文框架并如创建嵌入式数据库中所述,在Spring配置文件中将嵌入式数据库配置为一个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