Rollback時にflushしないSessionFactory
S2Hibernateを使って開発をしていて、例外発生時にS2SessionFactoryImplがセッションを閉じるときにflushしようとして更に例外が発生する、ということがありました。
で、closeSessionメソッドでロールバック中かどうかを判断して、ロールバックしてたらflushしない実装を作ってみました。
public void beforeCompletion() { //closeSession(); } public void afterCompletion(int arg0) { closeSession(); } private void closeSession() { final Transaction tx = getTransaction(); if (tx == null) return; final S2Session session; synchronized (this) { session = (S2Session) txSessions_.remove(tx); } if (session != null && session.isOpen()) { try { if (!isRolledBack(tx) && !session.isReadOnly()) session.flush(); } finally { Connection con = session.close(); ConnectionUtil.close(con); } } } private boolean isRolledBack(Transaction tx) { try { return tx.getStatus() == Status.STATUS_ROLLEDBACK; } catch (SystemException e1) { return true; //例外発生時はこれでいいのか? } }
ちょっと手書きで直したので変なところがあるかもしれないですけど、大体こんな感じ。
beforeCompletionメソッドじゃなくて、afterCompletionメソッドでcloseSessionメソッドを呼んでいるところがポイントです。beforeCompletionメソッドで呼び出した場合org.seasar.extension.jta.TransactionImplのgetStatusメソッドはStatus.STATUS_ACTIVE(値は0)を返すためロールバックしたかどうかが判断できないので、afterCompletionメソッドでcloseSessionメソッドを呼び出しています。
こういう実装をとりあえず使っているんですけど、JTA関係に自信がないのでid:kenichi_okazaki さんに聞いてみようと思って書いてみました。いかがでしょうか?