H2をインメモリで動かすときの注意
H2をインメモリで動かすときは
jdbc:h2:mem:test
みたいな感じでmemを付けて開いてあげます。
ただこのまま起動すると、ちょっと注意が必要でconnectionをcloseするとその時点でDBが消滅します。これ知らないと最初のcreate tableは成功しているのに、あとからinsertしようとするとテーブルないとか言われるよ!みたいなことではまります(お、お、おれじゃないからな!)。
消えないようにするにはconnectionをひとつ開いてどっかでcloseせずに保持しておくか、オプションでDB_CLOSE_DELAYを付けてあげるかどちらかです。
詳しくはテストを。
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.h2.Driver; import org.junit.Test; public class H2MemDbTest { @Test(expected = SQLException.class) public void コネクションをcloseするとDBが消える() throws Exception { Driver.load(); Connection con1 = DriverManager.getConnection("jdbc:h2:mem:test"); Statement st1 = con1.createStatement(); st1.execute("create table test (id int primary key,name varchar)"); st1.execute("insert into test values (1, 'hoge')"); ResultSet rs1 = st1.executeQuery("select * from test"); assertThat(rs1.next(), is(true)); st1.close(); con1.close(); Connection con2 = null; Statement st2 = null; try { con2 = DriverManager.getConnection("jdbc:h2:mem:test"); st2 = con2.createStatement(); // 一度コネクションクローズしているのでテーブルが見つからず // SQLExceptionがthrowされる st2.executeQuery("select * from test"); } finally { st2.close(); con2.close(); } } @Test public void コネクションをひとつ開きっぱなしにすると問題ない() throws Exception { Driver.load(); Connection con1 = DriverManager.getConnection("jdbc:h2:mem:test"); Statement st1 = con1.createStatement(); st1.execute("create table test (id int primary key,name varchar)"); st1.execute("insert into test values (1, 'hoge')"); ResultSet rs1 = st1.executeQuery("select * from test"); assertThat(rs1.next(), is(true)); st1.close(); // con1はクローズしない Connection con2 = DriverManager.getConnection("jdbc:h2:mem:test"); Statement st2 = con2.createStatement(); ResultSet rs2 = st2.executeQuery("select * from test"); assertThat(rs2.next(), is(true)); st2.close(); con2.close(); con1.close(); } @Test public void DB_CLOSE_DELAYオプション付きで最初に開く() throws Exception { Driver.load(); Connection con1 = DriverManager.getConnection("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); // DB_CLOSE_DELAYオプション付きで開く Statement st1 = con1.createStatement(); st1.execute("create table test (id int primary key,name varchar)"); st1.execute("insert into test values (1, 'hoge')"); ResultSet rs1 = st1.executeQuery("select * from test"); assertThat(rs1.next(), is(true)); st1.close(); con1.close(); Connection con2 = DriverManager.getConnection("jdbc:h2:mem:test"); Statement st2 = con2.createStatement(); ResultSet rs2 = st2.executeQuery("select * from test"); assertThat(rs2.next(), is(true)); st2.close(); con2.close(); } }
ちなみにH2の中のDbStarter(Webアプリ起動時にH2立ち上げてくれるかわいい娘)は
localServletContext.setAttribute("connection", this.conn);
とかやってServletContextにconnectionを1つ保持するようになっているようですね。
最近もっぱらDB周りのユニットをテスト書くときは、H2をテストケースの前に起動してみたいなことをやります。爆速で感謝感謝であります。