在同一个H2内存数据库上建立多个连接

19 浏览
0 Comments

在同一个H2内存数据库上建立多个连接

我经常遇到同样的问题:我想使用内存数据库对我的DAO进行单元测试。我正在使用H2,但我认为与HSQLDB的问题基本相同。我的单元测试包括三个步骤:

  • 创建数据库并设置数据库架构(例如使用SQL脚本)
  • 在数据库中插入测试所需的数据(例如使用DbUnit)
  • 执行实际测试

在非常简单的情况下,可以使用同一个连接来完成这三个步骤,但是当情况变得稍微复杂一些时(例如使用框架来查询数据库而不是使用直接的PreparedStatements),则需要每个步骤使用一个连接。

问题:只要连接关闭,数据库似乎就被删除了。如何解决这个问题?

0
0 Comments

在处理这个问题时,H2数据库的文档给出了两个提示:

有时需要对同一个内存数据库进行多个连接。在这种情况下,数据库URL必须包含一个名称。例如:jdbc:h2:mem:db1。只有在同一个虚拟机和类加载器环境中使用此URL才能访问相同的数据库。

默认情况下,关闭对数据库的最后一个连接会关闭数据库。对于内存数据库,这意味着内容会丢失。为了保持数据库的打开状态,请在数据库URL中添加;DB_CLOSE_DELAY=-1。为了在虚拟机存活期间保持内存数据库的内容,请使用jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

因此,第一个解决方案是在h2 url中添加;DB_CLOSE_DELAY=-1。但我对此不太满意,因为它表示数据库将永远保留在内存中,而我希望它只在我的测试运行期间保持活动状态。

关于DB_CLOSE_DELAY的文档提供了更多信息:

设置关闭数据库的延迟时间(如果所有连接都已关闭)。值-1表示数据库直到将关闭延迟设置为其他值或调用SHUTDOWN之前都不会关闭。值0表示没有延迟(默认值;如果关闭对它的最后一个连接,则关闭数据库)。值1及更大的值表示在关闭最后一个连接后数据库保持打开的秒数。

文档还提供了其他解决方案的提示,例如在关闭之前给出一点延迟或手动调用SHUTDOWN(我还没有找到如何在内存数据库上使用它)。

最后,这是我解决问题的方法:由于数据库在关闭最后一个连接时关闭,我将在创建数据库时保持一个空连接打开,直到不再需要它。这个解决方法有点技巧性(只保持一个空闲连接以保持数据库活动基本上是一种浪费),但这是我迄今为止找到的最优雅的解决方案。以下是一个非常简化的抽象单元测试类的代码片段,说明了这个解决方案:

import org.h2.jdbcx.JdbcDataSource;
public abstract class AbstractTestDao {
private Connection blankConnection;
private DataSource dataSource;
protected DataSource getDataSource() {
    return dataSource;
}
public void setup() throws SQLException {
    JdbcDataSource jdbcDataSource = new JdbcDataSource();
    jdbcDataSource.setUrl("jdbc:h2:mem:test");
    this.dataSource = jdbcDataSource;
    this.blankConnection = dataSource.getConnection();
}
public void tearDown() throws SQLException {
    this.blankConnection.close();
}
}

子单元测试类将继承这个类,并使用提供的DataSource对象来初始化用于查询数据库的库,以及执行问题中列出的另外两个步骤。测试完成后,空连接将被关闭,内存数据库也将被关闭。

0