# 3.9嵌入式数据库支持

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

## 3.9.1 为什么要使用嵌入式数据库？

嵌入式数据库由于其轻量级的特性，因此在项目的开发阶段可能会很有用。 好处包括易于配置，快速启动时间，可测试性以及在开发过程中快速演化SQL的能力。

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

如果要在Spring ApplicationContext中将嵌入式数据库实例作为Bean公开，则可以在spring-jdbc命名空间中使用Embedded-database标记：

```markup
<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数据库，该数据库中使用SQL从类路径根目录中的schema.sql和test-data.sql资源中填充。 另外，作为最佳实践，将为嵌入式数据库分配一个唯一生成的名称。 嵌入式数据库作为javax.sql.DataSource类型的Bean在Spring容器中使用，然后可以根据需要将其注入到数据访问对象中。

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

EmbeddedDatabaseBuilder类提供了一种流畅的API，用于以编程方式构造嵌入式数据库。 当您需要在独立环境或独立集成测试中创建嵌入式数据库时，可以使用此方法，如以下示例所示：

```java
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()
```

您还可以使用EmbeddedDatabaseBuilder通过Java配置创建嵌入式数据库，如以下示例所示：

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

## 3.9.4 选择嵌入式数据库类型

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

* 使用HSQL
* 使用H2
* 使用Derby

**使用HSQL**

Spring支持HSQL 1.8.0及更高版本。如果未明确指定类型，则HSQL是默认的嵌入式数据库。要明确指定HSQL，请将嵌入式数据库标记的type属性设置为HSQL。如果使用构建器API，请使用EmbeddedDatabaseType.HSQL调用setType（EmbeddedDatabaseType）方法。

**使用H2**

Spring支持H2数据库。要启用H2，请将嵌入式数据库标记的type属性设置为H2。如果使用构建器API，请使用EmbeddedDatabaseType.H2调用setType（EmbeddedDatabaseType）方法。

**使用Derby** Spring支持Apache Derby 10.5及更高版本。要启用Derby，请将嵌入式数据库标记的type属性设置为DERBY。如果使用构建器API，请使用EmbeddedDatabaseType.DERBY调用setType（EmbeddedDatabaseType）方法。

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

嵌入式数据库提供了一种轻量级的方法来测试数据访问代码。下一个示例是使用嵌入式数据库的数据访问集成测试模板。当嵌入式数据库不需要在测试类之间重用时，使用这种模板可以一次性使用。但是，如果您希望创建一个在测试套件中共享的嵌入式数据库，请考虑使用Spring TestContext Framework并将嵌入式数据库配置为Spring ApplicationContext中的Bean，如使用Spring XML创建嵌入式数据库和创建一个嵌入式数据库中所述。以编程方式嵌入数据库。以下清单显示了测试模板：

```java
public class DataAccessIntegrationTestTemplate {

    private EmbeddedDatabase db;

    @Before
    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( /* ... */ );
    }

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

}
```

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

如果开发团队的测试套件无意中尝试重新创建同一数据库的其他实例，则开发团队经常会遇到错误。如果XML配置文件或@Configuration类负责创建嵌入式数据库，然后在同一测试套件（即，同一JVM进程）内的多个测试场景中重用相应的配置，则这很容易发生。集成测试针对其ApplicationContext配置仅在哪些bean定义配置文件处于活动状态方面有所不同的嵌入式数据库进行。

造成此类错误的根本原因是，如果未另行指定，Spring的EmbeddedDatabaseFactory（由\<jdbc：embedded-database> XML命名空间元素和EmbeddedDatabaseBuilder for Java配置在内部使用）会将嵌入式数据库的名称设置为testdb。对于\<jdbc：embedded-database>，通常为嵌入式数据库分配一个名称，该名称等于bean的ID（通常是类似于dataSource的名称）。因此，随后创建嵌入式数据库的尝试不会产生新的数据库。取而代之的是，相同的JDBC连接URL被重用，并且尝试创建新的嵌入式数据库实际上指向的是从相同配置创建的现有嵌入式数据库。

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

* EmbeddedDatabaseFactory.setGenerateUniqueDatabaseName（）
* EmbeddedDatabaseBuilder.generateUniqueName（）
* \<jdbc：embedded-database generate-name =“ true”……>

## 3.9.7 扩展嵌入式数据库支持

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

* 实现EmbeddedDatabaseConfigurer以支持新的嵌入式数据库类型。
* 实现DataSourceFactory以支持新的DataSource实现，例如用于管理嵌入式数据库连接的连接池。

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