こないだの続き。
昨日書いた日記の続きです。
dbunit + h2 database + domaでテスト環境を構築していてぶち当たった問題について書いた続きです。
問題は、dbunitを使ってテストしたい。データのリストアはトランザクションを使うのでロールバックで実現したい。けど、オートコミットをオフにしてもdomaでエラーが吐かれて実現できない。という事でした。
で、前回はそのエラーを別途、載せると書きましたが、コードを色々いじくっている内に出なくなってしまったので載せません。
なので、新たに調べていて分かった事を書きます。
domaでトランザクションを使おうと思い、ちょくちょく調べていましたが、
aptで自動生成される「xxxxImpl.java」に以下の通り、コネクションをクローズしている箇所がありました。
public int[] execute() { ...中略... } finally { JdbcUtil.close(preparedStatement, query.getConfig() .getJdbcLogger());★ } } finally { JdbcUtil.close(connection, query.getConfig().getJdbcLogger()); } ^^^^^★
予想としては、ここでクローズが走るとコミットも自動的にかかってしまうのでは??
と思ったわけです。いくらオートコミットをオフにしても、ここでコミットされてしまうとトランザクションが実現できないのではないかと。でも、それもおかしい気がするので何か回避策があるのではと思って考え、人に聞き、そして以下の方法にしました。
「プロキシパターン、リフレクションを使って、close()が呼ばれた時のみ何もしなくする。」
ざっくりとコードを以下に載せます。
※処理内容はまだ把握中です。
final SimpleDataSource ds = new SimpleDataSource() { Connection connWrapper; @Override public Connection getConnection() throws SQLException { if (conn == null) { conn = dataSource.getConnection(); connWrapper = (Connection) Proxy.newProxyInstanceUserDaoTest.class.getClassLoader(), new Class<?>[] { Connection.class }, new Java.lang.reflect.InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("close")) return null; return method.invoke(conn, args); } }); } return connWrapper; } };
結果としてはclose()が呼ばれた時だけ何もしない処理を書いてあげて、クローズとコミットをさせないようにしています。
これで、close()実行時にコミットが走る事もなくなり、無事にトランザクション処理が実現できるようになります。
本当は、domaで何か回避策が見つかればそちらをやってみようかと思いましたが、今のところ発見できていません。