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.