質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Spring

Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

トランザクション

トランザクションとは、関連・依存する処理を一連の不可分な処理単位として扱う処理方式を指します。トランザクションとして管理された処理は「すべて成功」か「すべて失敗」のいずれかであることが保証される。処理に失敗した場合は、一連の処理がロールバックされます。

Q&A

1回答

18873閲覧

springにおける複数トランザクション管理

hirame503

総合スコア8

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Spring

Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

トランザクション

トランザクションとは、関連・依存する処理を一連の不可分な処理単位として扱う処理方式を指します。トランザクションとして管理された処理は「すべて成功」か「すべて失敗」のいずれかであることが保証される。処理に失敗した場合は、一連の処理がロールバックされます。

0グッド

0クリップ

投稿2016/09/22 14:56

初めて利用させて頂きます。

【状態】
springで独自にAPIを作成しております。
API実行時に、以下のような形で
トランザクション開始を明示しております。

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);

その後、APIで別クラス(以下Bクラス)を呼び出します。
Bクラス側ではテーブルのupdateをしており、
直接JDBCのConnectionを取得して実行しています。

Connection con = DataSorceUtil.getConnection(jdbcTemplate.DateSouce)

Bクラス側でcommitまで完了させ、その後、
API側でロールバックを完了させようとすると、
exceptionが発生してしまう状態です。
なお、APIとBクラスがアクセスするDBはORACLE11gで、同じDB内の別テーブルをそれぞれが更新します(スキーマは同一です)

【フロー図】
API実行

APIでトランザクション開始

APIがBクラス(共通処理的な)呼出

Bクラスでトランザクション開始

Bクラスがコミット実行。Bクラス動作終了。

APIに処理が戻ってきた後、エラー処理でロールバック実行

APIでexception発生

【実現したいこと】
・APIはロールバックを行ってテーブル更新させたくないが、Bクラスはコミットまで完了させたい
(クラス単位で、途中でトランザクション終了させることなく、別々にトランザクション管理をしたい)

【質問】
・複数のトランザクション管理を明示的に行う事は可能なのでしょうか?
・お互いのトランザクション管理が干渉しないようにする為にはどういった実装が理想でしょうか?
・複数のトランザクション管理について、参考になるページなどありましたらご教示頂ければ幸いです。

以上、よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

###方針
よくあるのは、業務トランザクションの成功/失敗にかかわず、ログだけはデータベースに書いておきたい、という要件です。

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章のトランザクションマネージャの解説を読んでみたところ、上記のように自分でカスタムコードを書く必要がないことがわかりました。うんと簡単です。

方法

  1. トランザクションマネージャを使う。
  2. 外側のトランザクションを開始する。

  トランザクションの伝搬属性を、PROPERGATION_REQUIREDにする。
3. 内側のトランザクションを開始する。(別に開始してください)
トランザクションの伝搬属性を、PROPERGATION_REQUIRES_NEWにする。

PROPERGATION_REQUIRES_NEWを指定することで、suspend, resumeが自動的に行われる。
(動作させて確認したわけではありません。(それじゃダメじゃん 。はい、時間が取れればやってみます。))

問題が出そうなところは以下の点です。

トランザクションマネージャーの違いによる動作の違い
同様に、DAOの違いによる動作の違い
データソースの定義による動作の違い
宣言型トランザクションの設定の間違い

どなたか、親切な方、コードサンプルをポストしてください。

投稿2016/09/22 18:18

編集2016/09/23 09:19
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問