4

I have the same problem on a regular basis: I want to perform unit testing on my DAO using an in-memory database. I am using H2, but I believe the problem is pretty much the same with HSQLDB. My unit test involves three steps:

  • create database and setup database schema (using SQL script for instance)
  • insert required data for the test in the database (ex: with DbUnit)
  • perform actual testing

In very simple situations, it is possible to use the very same connection for all three steps, but as soon as things get a little more complicated (for instance when using a framework for querying the database rather than using direct PreparedStatements), one connection per step is required.

Problem: the database seems to be dropped as soon as the connection is closed. How to solve it?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Aldian
  • 2,592
  • 2
  • 27
  • 39
  • Be aware the in-memory database is discarded, by default, when the connection closes. You can override this behavior. See: [*Keep H2 in-memory database between connections*](https://dba.stackexchange.com/q/224338/19079) and [*H2 in-memory database. Table not found*](https://stackoverflow.com/q/5763747/642706) – Basil Bourque Dec 06 '18 at 21:32

1 Answers1

4

Regarding this topic, H2 documentation gives two hints:

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.

So first solution was to add ;DB_CLOSE_DELAY=-1 to h2 url. But I was a bit unsatisfied with it since it says that the database will stay in memory forever while I want it to live only as long as my test is running.

Documentation about DB_CLOSE_DELAY gives more info:

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.

It hints for others solutions like giving a little delay before shutdown or manually calling SHUTDOWN (which I didn't find out how to use on a in-memory database yet).

Finally here is how I sorted it out: since the database close when the last connection is closed, I will just keep open a blank connection from the time I create the Database until when I won't need it anymore. That workaround is a bit hacky (leaving a spare connection open only to keep de database alive is basically a waste), but it is the most elegant solution I have found so far. Here is a very simplified snippet of abstract unit test class that illustrate this solution:

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

Children unit test classes will inherit this one and use the provided DataSource object to initalize the library used to query the database, as well as to peform the two other steps listed in the question. Once the test is finished, the blank connection is closed, and so is the in-memory database.

Aldian
  • 2,592
  • 2
  • 27
  • 39