多次连接同一个H2内存数据库

5
我经常遇到相同的问题: 我想使用内存数据库来对我的DAO进行单元测试。我使用的是H2,但我认为在HSQLDB方面问题基本相同。我的单元测试包括三个步骤:
  • 创建数据库并设置数据库模式(例如使用SQL脚本)
  • 向数据库插入所需的测试数据(例如使用DbUnit)
  • 执行实际测试
在简单的情况下,可以使用完全相同的连接进行这三个步骤,但是一旦事情变得更加复杂(例如使用框架查询数据库而不是使用直接的PreparedStatements),每个步骤都需要一个连接。
问题是: 当连接关闭时,数据库似乎立即被删除。如何解决这个问题?

请注意,默认情况下,内存数据库在连接关闭时被丢弃。您可以覆盖此行为。请参见:在连接之间保留H2内存数据库H2内存数据库。表未找到 - Basil Bourque
1个回答

5
关于这个主题,H2文档提供了两个提示:(链接) 有时需要多个连接到同一个内存数据库。在这种情况下,数据库URL必须包含名称。例如:jdbc:h2:mem:db1。仅在相同的虚拟机和类加载器环境中使用此URL访问相同的数据库。
默认情况下,关闭对数据库的最后一个连接会关闭数据库。对于内存数据库,这意味着内容会丢失。要保持数据库打开,请将;DB_CLOSE_DELAY=-1添加到数据库URL。要使内存数据库的内容保持活动状态,只要虚拟机处于活动状态,就可以使用jdbc:h2:mem:test;DB_CLOSE_DELAY=-1。
因此,第一种解决方案是将;DB_CLOSE_DELAY=-1添加到h2 URL。但我对此不太满意,因为它说数据库将永远驻留在内存中,而我希望它只在我的测试运行期间存在。
关于DB_CLOSE_DELAY的文档提供了更多信息:
如果所有连接都关闭,则设置关闭数据库的延迟。值-1表示数据库永远不会关闭,直到将关闭延迟设置为其他值或调用SHUTDOWN。值0表示没有延迟(默认值;如果关闭对它的最后一个连接,则关闭数据库)。值1及更大值表示关闭最后一个连接后,数据库保持打开状态的秒数。
它提供了其他解决方案的提示,例如在关闭之前给予一点延迟或手动调用SHUTDOWN(我还没有找到如何在内存数据库上使用它)。
最后,这是我解决问题的方法:由于数据库在关闭最后一个连接时关闭,因此我将从创建数据库开始保持打开一个空白连接,直到不再需要它为止。这个解决方法有点hacky(只为保持数据库活动而留下一个备用连接基本上是浪费),但这是我目前找到的最优雅的解决方案。以下是抽象单元测试类的非常简化的代码片段,说明了这个解决方案:
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对象初始化用于查询数据库的库,以及执行问题中列出的另外两个步骤。一旦测试完成,空连接将被关闭,内存中的数据库也将被关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接