[Seasar-user:22007] Re: 一意制約違反発生時の更新処理について

Koichi Kobayashi [E-MAIL ADDRESS DELETED]
2014年 12月 9日 (火) 03:48:26 JST


小林 (koichik) です。

おそらくですが、以下のドキュメントに書いてある
ことかと思います。

http://s2container.seasar.org/2.4/ja/tx.html

「トランザクションを開始した場合でも引き継いだ場合でも、
このインターセプタが適用されたメソッドが例外をスローした場合は、
例外の種類に応じてトランザクションがロールバックされるように
マークします。」

つまり、

public void foo() {
  try {
    bar();
  } catch (...) {
    ...
  }
}

public void bar() {
  throw ...;
}

foo()とbar()の両方に宣言的トランザクションが
適用される場合、foo()でトランザクションを開始して
bar()はそのトランザクションの中で呼び出されますが、
bar()がスローする例外によってfoo()で開始した
トランザクションは「ロールバックされるようにマーク」
されます。
そのため、foo()でその例外をキャッチしても、
foo()からリターンする際にトランザクションは
ロールバックされます。

対策としては、トランザクション境界の中で呼び出される
メソッド (上記のbar()に相当) には宣言的トランザクションを
設定しないようにするか、特定の例外ではロールバックと
マークされないように設定する方法があります。
# 前者の方がよいかと思います。

後者については上記ドキュメントの「例外発生時の動作」に
説明があります。
実際に設定する場合はj2ee.diconをコピーして、
S2にバンドルされているejb3tx.diconを参考に
一意制約違反発生時の例外でロールバックしないように
設定してください。


On Mon, 8 Dec 2014 19:02:32 +0900, あきやまじろう <mayama0130 @ gmail.com> wrote:

> お世話になっております。あきやまと申します。
> 
> 一意制約違反発生時の更新処理について教えてください。
> 
> [動作環境]
> ・S2Container 2.4.45
> ・PostgreSQL 9.0.13
> 
> 現在、以下の処理を実装しようとしていますが、
> 
> 1.トランザクション開始(トランザクションA)
> 2.SELECT FOR UPDATEでAテーブルからレコードを取得
> 3.トランザクション開始(トランザクションB)
> 4.BテーブルのレコードをSELECT FOR UPDATEで取得
> →取得できなかった場合、レコードを登録
> →一意制約違反が発生した場合、レコードを更新
> 5.トランザクションBをコミット
> 6.CテーブルのレコードをSELECT FOR UPDATEで取得
> →取得できなかった場合、レコードを登録
> →一意制約違反が発生した場合、レコードを更新
> 7.トランザクションCをコミット
> 8.トランザクションAをコミット
> 
> 項番4で一意制約違反が発生した場合にレコードを更新したいのですが、
> 「既にロールバックとしてマークされています」とログ出力され、更新できなくなり困っています。
> 項番1から8までをtry-catchして、項番1から再トライすれば、うまくいくのですが、
> 項番6でも一意制約違反の可能性があり、その場合try-catchをネストしないといけないので、できれば避けたいです。
> 何かいい対処方法があれば、ご教授の程よろしくお願いします。


-- 
{
  name: "Koichi Kobayashi",
  mail: "koichik @ improvement.jp",
  blog: "http://d.hatena.ne.jp/koichik/",
  twitter: "@koichik"
}



Seasar-user メーリングリストの案内