Transaction is not active: javax.transaction.RollbackException: The transaction is not active!
というエラーと奮闘した話(JBoss AS5.1.0GA/Seam2.2/EJB3)
メッセージでそのままぐぐればTech Team Lead Newsの記事が見つかるので、トランザクションタイムアウトの値を増やしてあげればよい、という話。
…なんだけど、結局トランザクションタイムアウトを増やしても、どれくらいの値が最適なのか、とか、確率が減るだけで起こる可能性はなくなってない、といった問題は残ったまま。そんなわけで、エラーをもう少し詳しく調べることにした。
よりきれいな対処のためにはJBoss、というか、Java EEのトランザクション属性についての理解が必要だったので、ここでまとめておく(以前にも似たようなことでハマった記憶があるけど)。トランザクション属性についての説明を見れば、それぞれの意味はわかるけど、どう使い分ければよいのかの指針が完全に抜け落ちていたなぁ。
個人的な感想としては、各トランザクション属性は、そもそもそのトランザクションを使うのかどうか、呼び出し元のトランザクションが開始されている時にそのトランザクションが中断されるのかどうか、という観点を意識して選択する必要があると感じた。
トランザクション属性 | トランザクションを使う? | 呼び出し元のトランザクションは中断? (呼び出し元のトランザクションが開始されている時) |
---|---|---|
MANDATORY | ○ | × |
REQUIRED | ○ | × |
REQUIRES_NEW | ○ | ○ |
SUPPORTS | △ | × |
NOT_SUPPORTED | × | ○ |
NEVER | × | × |
以上を元に、トランザクションタイムアウトに話を戻すと、呼び出し元のトランザクションが中断しても、中断している間もトランザクションタイムアウトの計算時間はカウントされている、という点が重要。
例
例として以下のケースを考えてみる。
メソッドBとメソッドCにそれぞれ5秒ずつかかった場合、メソッドDが呼ばれた時(正確には、メソッドCを抜けた後のメソッド)に、トランザクションタイムエラーが起こる。ここが勘違いしていたポイントその1で、REQUIRES_NEWで新しくトランザクションを開始しているし、そもそも「中断」なんだから、メソッドAのトランザクションタイムアウトはメソッドBの実行時間が除外されて計算されると思っていた。
また、トランザクションタイムアウトエラーの発生ポイントは、タイムアウト時間を超過してすぐではなく、その次のトランザクション境界でトランザクションを使う時。今回の例では、メソッドC実行時に10秒のタイムアウトを超えるので、メソッドC実行中にエラーが起こるものだと勘違いしていたけど、実際はそうではない。
注 この辺は、もしかするとこれはJBoss ASの実装に依存した話かもしれない…。