menu
書いてる野郎
orebike@gmail.com
SAStruts というよりかは S2JDBC とかの領域か?
SAStrutsではデフォルトでActionメソッド単位でトランザクションが開始されることになっている。 内部で例外が発生して、それを呼び出し元のコントローラーまでぶん投げるとActionメソッド内でやった処理が全部自動でロールバックされる。
SAStrutsではデフォルトで全てのメソッドは何かのトランザクションが開始されていたらそれを引き継ぐという設定になっている。 なのでActionから開始されたトランザクションをすべてのメソッドが引き継いでいるという仕掛け。
Action 単位でロールバックせず、呼び出しているServiceのメソッド単位でトランザクション管理したいときがある。そのような場合はどう実装すればよいか。
※【注意】 ここでやり方をメモしておくが、基本的にトランザクションは Action 単位でやるべき。分割するとわけがわからなくなるし、テスト困難になるのでやらないほうがいい。トランザクションの制御は常に Action 側でコントロールすべし。
メソッドにアノテーションをつけると現在のトランザクションを一時中断(コミットでは無い)して新たなトランザクションを開始する。
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void hoge() throws Exception { //何か処理 }
のようにすると呼び出した元のメソッド(今ならばhogeを呼び出した何かのメソッド)が引き継いでいるトランザクションを一旦お休みにして、 自分(今ならhogeメソッド)から新しいメソッドを開始する。
他のメソッドはデフォルトで開始されているトランザクション(今ならばhogeが開始したトランザクション)を引き継ぐのでhoge内部と外部でトランザクションを分けることができる
hogeメソッドが終われば、それはコミットされてお休みにしていたトランザクションが復帰する。 当然hogeメソッド内で例外が発生すればhogeメソッド内で変更した処理のみがロールバックする
注意する必要があるのはお休みしているトランザクションはコミットされているわけでは無いので、hoge内部からは見えなくなってしまうということだ。トランザクションは入れ子になっているわけじゃなくて、単純に分かれている。
この問題はテストの際にも現れる。 S2Junit4でテストした場合テストデータを投入して、テスト、終了後ロールバックという流れになるが、ロールバックするということはテスト自体がトランザクションを持っているということになる。
トランザクション分割指定したメソッドをテストする場合、 分割されてしまっているのでテスト自体の(コミット予定の無い)トランザクションと、テスト対象のトランザクションが別になってしまい、テスト対象自体もトランザクションが終わってないので結果の検証ができないという問題が発生する。
このような場合テストメソッドに
@TxBehavior(TxBehaviorType.NONE)
をつけて、テストのトランザクション開始自体をやめてしまう。
こうすると、トランザクションが無いのでテスト側で随時コミットされた内容を把握することができるようになる。 ロールバックは自分でやる必要がでてくるが・・・
というようにトランザクション分割をしたい状況というのはあるが、そうした場合新たなトランザクションの内容を呼び出し元トランザクション内で参照しないという配慮が必要になる。
呼び出されたところでは開始とコミットのタイミングが順に一致しているなら呼び出してもOK