###方針
よくあるのは、業務トランザクションの成功/失敗にかかわず、ログだけはデータベースに書いておきたい、という要件です。
Springのクラスははっきりと把握していないので、JTAを適用する一般論として書きます。TransactionManagerのAPIを使います。TransactionManagerはSpringのAPIから取得してください。同じことが、EJBのコンテナ管理トランザクションで、トランザクション属性をRequiresNewにすると、できます。
API実行
↓
APIでトランザクション開始
↓
%%%%%%%%%%%%%%%%%%%%%%%%%%%
トランザクションをsuspend()
%%%%%%%%%%%%%%%%%%%%%%%%%%%
↓
APIがBクラス(共通処理的な)呼出
↓
Bクラスでトランザクション開始
↓
Bクラスがコミット実行。Bクラス動作終了。
↓
%%%%%%%%%%%%%%%%%%%%%%%%%%%
トランザクションをresume()
%%%%%%%%%%%%%%%%%%%%%%%%%%%
↓
APIに処理が戻ってきた後、エラー処理でロールバック実行
↓
APIでexception発生
B は外側のトランザクションのことを知らなくても良いので、自分のトランザクションだけに注力でます。
###Java EE API
docs.oracle.com/javaee/7/api/index.html?javax/transaction/TransactionManager.html
トランザクションの一時停止
TransactionManager.suspend()
Suspend the transaction currently associated with the calling thread and return a Transaction object that represents the transaction context being suspended.
トランザクションの再開
TransactionManager.resume(Transaction tobj)
Resume the transaction context association of the calling thread with the transaction represented by the supplied Transaction object.
###B のトランザクション管理
トランザクションの開始
JTAのAPIは、TransactionManager.begin()になりますが、Springはどうするのですか?新なトランザクションのために、AOPのProxyがここに必要でしょうか。
Connectionの取得
外側のトランザクションとは別のトランザクションになるので、新たにConnectionを取得する必要があります(XAResourceのトランザクションへの参加)。データソースはXAでなければなりません。
コミット
ロールバック
Springのやりかたでやってください。ただしBのトランザクションをロールバックさせるために例外を投げるのであれば、B のスコープ内で処理する必要があります。外側に伝播させたいのなら、B を一度ロールバックしてから、伝えてください。
その他
外側のトランザクションで更新するレコードを、B のトランザクションで更新しないでください。別トランザクションです。排他制御され、B の処理が止まります。
代替案
JTAを使わないトランザクション管理。XAではないデータソースを別に用意。Connectionを取得して、Connection.commit()/.rollback()処理を行う。TransactionManagerを使わないやり方です。
以上、ひとつの解決策として提案します。
###B のトランザクション管理(追記)
トランザクションのsuspend/resumeは、Bでやる方が開発に影響がでないでしょう。TransactionManager.status()でトランザクションの状態を取得できます。トランザクションがあればsuspend/resumeする。そして自分のトランザクションを開始する。
###参考書の情報(追記)
技術評論社の『改訂新版 Spring入門』を買いました。第4章のトランザクションマネージャの解説を読んでみたところ、上記のように自分でカスタムコードを書く必要がないことがわかりました。うんと簡単です。
方法
- トランザクションマネージャを使う。
- 外側のトランザクションを開始する。
トランザクションの伝搬属性を、PROPERGATION_REQUIREDにする。
3. 内側のトランザクションを開始する。(別に開始してください)
トランザクションの伝搬属性を、PROPERGATION_REQUIRES_NEWにする。
PROPERGATION_REQUIRES_NEWを指定することで、suspend, resumeが自動的に行われる。
(動作させて確認したわけではありません。(それじゃダメじゃん 。はい、時間が取れればやってみます。))
問題が出そうなところは以下の点です。
トランザクションマネージャーの違いによる動作の違い
同様に、DAOの違いによる動作の違い
データソースの定義による動作の違い
宣言型トランザクションの設定の間違い
どなたか、親切な方、コードサンプルをポストしてください。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。