java - 与同一 H2 内存数据库建立多个连接

标签 java unit-testing jdbc h2

<分区>

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

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

在非常简单的情况下,可以对所有三个步骤使用完全相同的连接,但是一旦事情变得有点复杂(例如,当使用框架查询数据库而不是直接使用 PreparedStatements 时),每一步需要一个连接。

问题:数据库似乎在连接关闭后就被丢弃了。如何解决?

最佳答案

关于这个主题,H2 documentation给出两个提示:

Sometimes multiple connections to the same in-memory database are required. In this case, the database URL must include a name. Example: jdbc:h2:mem:db1. Accessing the same database using this URL only works within the same virtual machine and class loader environment.

By default, closing the last connection to a database closes the database. For an in-memory database, this means the content is lost. To keep the database open, add ;DB_CLOSE_DELAY=-1 to the database URL. To keep the content of an in-memory database as long as the virtual machine is alive, use jdbc:h2:mem:test;DB_CLOSE_DELAY=-1.

所以第一个解决方案是将 ;DB_CLOSE_DELAY=-1 添加到 h2 url。但我对它有点不满意,因为它说数据库将永远保留在内存中,而我希望它只在我的测试运行时存在。

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

Sets the delay for closing a database if all connections are closed. The value -1 means the database is never closed until the close delay is set to some other value or SHUTDOWN is called. The value 0 means no delay (default; the database is closed if the last connection to it is closed). Values 1 and larger mean the number of seconds the database is left open after closing the last connection.

它暗示了其他解决方案,例如在关机前稍微延迟或手动调用 SHUTDOWN(我还没有找到如何在内存数据库上使用它)。

最后我是这样整理的:由于数据库在最后一个连接关闭时关闭,所以我将在创建时保持打开一个空白连接数据库,直到我不再需要它为止。该解决方法有点老套(仅保留一个备用连接以保持数据库 Activity 基本上是一种浪费),但它是迄今为止我找到的最优雅的解决方案。这是一个非常简化的抽象单元测试类片段,用于说明此解决方案:

import org.h2.jdbcx.JdbcDataSource;
public abstract class AbstractTestDao {

private Connection blankConnection;

private DataSource dataSource;

protected DataSource getDataSource() {
    return dataSource;
}

@Before
public void setup() throws SQLException {
    JdbcDataSource jdbcDataSource = new JdbcDataSource();
    jdbcDataSource.setUrl("jdbc:h2:mem:test");
    this.dataSource = jdbcDataSource;

    this.blankConnection = dataSource.getConnection();
}

@After
public void tearDown() throws SQLException {
    this.blankConnection.close();
}
}

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

关于java - 与同一 H2 内存数据库建立多个连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49921752/

相关文章:

c# - 单元测试 Web 服务方法

java - 将新的 Java Resultset 对象分配给现有的结果集对象,然后关闭原始的 ResultSet 对象会导致新创建的结果集对象被关闭吗?

java - 从存储过程返回的 STRUCT 中读取 ARRAY

java - 为函数或方法创建位掩码参数

java - OnListItemClick 空指针异常

java - 在类中测试序列化方法的正确方法如何?

java - 更新在 JDBC 中不起作用

java - gwt - 在 RPC 调用中使用 List<Serializable>?

java - SocketTimeoutException 和 Jetty 的问题

android - 如何使用 Gradle 命令在 Android 中运行单个测试类?