- h2database 官方文件 https://www.h2database.com/html/main.html
h2database 是一個 Java base database ,這篇文章主要是介紹如何使用 h2database 來做 MySQL Unit Test ,網路上可以找到很多種寫 MySQL unit test 的工具,有些非常笨重光是起 MySQL server 就花掉好幾分鐘,而我使用 h2database 後覺得非常不錯,執行超級快速。
h2database 官方提供的各種 database 比較。
H2 | Derby | HSQLDB | MySQL | PostgreSQL | |
---|---|---|---|---|---|
Pure Java | Yes | Yes | Yes | No | No |
Memory Mode | Yes | Yes | Yes | No | No |
Encrypted Database | Yes | Yes | Yes | No | No |
ODBC Driver | Yes | No | No | Yes | Yes |
Fulltext Search | Yes | No | No | Yes | Yes |
Multi Version Concurrency | Yes | No | Yes | Yes | Yes |
Footprint (embedded) | ~2 MB | ~3 MB | ~1.5 MB | — | — |
Footprint (client) | ~500 KB | ~600 KB | ~1.5 MB | ~1 MB | ~700 KB |
h2database 有三種模式,分別是 in-memory
, embedded
, Server
,這篇文章只說明如何使用 in-memory mode & MyBatis 來跑 unit test。
首先在 pom.xml 加入 h2 dependency 。
- <dependency>
- <groupId>com.h2database</groupId>
- <artifactId>h2</artifactId>
- <version>1.4.200</version>
- <scope>test</scope>
- </dependency>
搭配 MyBatis
MyBatis config.xml 加入以下設定, jdbc:h2:mem
代表使用 in-memory mode ,;DB_CLOSE_DELAY=1
這個參數是指當 connection 斷掉後保留 db 的資料,不要清空,如果沒有加這個值 connection 一斷,下次再連線就會發現資料不見了。
- <environments>
- <environment id="unitTest">
- <transactionManager type="JDBC">
- <property name="" value="" />
- </transactionManager>
- <dataSource type="POOLED">
- <property name="driver" value="org.h2.Driver" />
- <property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
- <property name="username" value="root" />
- <property name="password" value=""/>
- </dataSource>
- </environment>
- </environments>
Java Code 如下,如果我們是使用 in-memory mode, session
- public class H2database {
- private static SqlSessionFactory sqlSessionFactory = null;
- // keep session
- private static SqlSession session = null;
- public void startServer() throws Exception {
- Reader reader = Resources.getResourceAsReader(
- "mybatis.xml"
- );
- if (null == sqlSessionFactory) {
- sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader, "unitTest");
- Connection conn = null;
- try {
- session = sqlSessionFactory.openSession();
- conn = session.getConnection();
- ScriptRunner runner = new ScriptRunner(conn);
- runner.setLogWriter(null);
- FileReader r = new FileReader(unitSql);
- runner.runScript(r);
- } finally {
- if (null != reader) reader.close();
- }
- }
- }
mock close method,目前不知道為什麼,我已經有加 ;DB_CLOSE_DELAY=-1
, testing code 中有 close session 是不會清空資料,但是如果被測試的 object 有做 session close 的動作,還是會發生資料不見的問題,只好 mock close = doNothing 解掉這個問題。
- doNothing().when(session).close();
搭配 Java JDBC
- DriverManager.registerDriver(new org.h2.Driver());
- conn = DriverManager.getConnection("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE", "root", "");
- // To create table
- String query = String.join("",
- "CREATE TABLE IF NOT EXISTS `tableName` (",
- "`id` varchar(16) NOT NULL,",
- "`name` varchar(64) NOT NULL,",
- "PRIMARY KEY (`id`,`name`)",
- ");");
- PreparedStatement pstmt = conn.prepareStatement(query);
- pstmt.execute();
- // To insert data
- String query = String.format("insert into `%s` (`id`, `name`) values ('%s', '%s')", table, id, name);
- PreparedStatement pstmt = conn.prepareStatement(query);
- pstmt.execute();