[Seasar-user:17352] Re: トランザクション処理について

Koichi Kobayashi [E-MAIL ADDRESS DELETED]
2009年 5月 1日 (金) 00:00:02 JST


小林 (koichik) です.

Date:    Thu, 30 Apr 2009 22:18:13 +0900
From:    岩元 もぁーぃ <[E-MAIL ADDRESS DELETED]>
To:      <[E-MAIL ADDRESS DELETED]>
Subject: [Seasar-user:17350] トランザクション処理について

> 1トランザクションの処理は以下の通りです。
> 
>  1.あるテーブルのある項目の最大値(カウンタみたいなもの)を取得する。
>  2.取得した内容をインクリメントする。
>  3.2でインクリメントした項目をキーとして2つのテーブル(1のテーブルを含む)にInsertを行う。
>  4.3でInsertした内容を取得して、画面に表示する。

このやり方だと複数のトランザクションが並行に
実行された場合,1 で同じ値を読み取ってしまい,
3 で同じキーを持つレコードを insert してしまいます.
なので,

> 現在起きている現象は、処理3で実施したsave()が処理4のcreateQuery実行時に反映されているようで
> エラーが発生しない間は問題ないのですが、一度エラーが発生すると処理1のcreateQuery実行時に
> ERROR: duplicate key value violates unique constraint "aaaaa_bbbbb_pkey"が発生し、
> それ以降の処理全てを実行することができない状態となっています。
> 
> 最初に出力されるエラー内容は以下の通りです。
> 
> [ESSR0072]SQLで例外(SQL=[insert into *******_t_answer_history (answer_starttime, answer_endtime, get_total_score, right_per_answer, necessary_time, pass_ornot, add_user, update_user, user_id, lesson_id, answer_count) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)], ErrorCode=0, SQLState=23505)が発生しました
> ERROR: duplicate key value violates unique constraint "*******_t_answer_history_pkey"

となります.
1 で select 〜 for update を使うか,2 の update 文の
where に更新前のカウンタの値を含めて更新できた行数を
チェックする (0 行の場合はリトライする) などしてください.

> 大変恐縮ですが、以下のdiconファイルを基にトランザクション処理を確認したところ、
> 下記ログのようなエラーが発生しているのですが、その場合の修正方法をご教授願えませんでしょうか。
(略)
> org.seasar.framework.exception.InvocationTargetRuntimeException: [ESSR0043]com.*******.signup.service.ConfirmServiceImpl$$EnhancedByS2AOP$$47b232が呼び出した対象が不正です。理由はorg.seasar.framework.exception.SIllegalStateException: [ESSR0311]トランザクションが開始されていません

このメッセージは文字通りトランザクションを開始せずに
JDBC コネクションを取得した場合にスローされます.
j2ee.dicon の

>     <component name="connectionPool"
>         class="org.seasar.extension.dbcp.impl.ConnectionPoolImpl">
>         <property name="timeout">600</property>
>         <property name="maxPoolSize">30</property>
>         <property name="allowLocalTx">false</property>

この allowLocalTx が true (デフォルト) の場合は
トランザクションが開始されていなくても,自動
コミットモードのコネクションを取得することが
できます.

しかし,この j2ee.dicon では allowLocalTx が
false であるため,例外がスローされます.

>     at com.*******.signup.service.ConfirmServiceImpl.<init>(ConfirmServiceImpl.java:35)

このクラスのコンストラクタで Hibernate の Session を
使用していますが,トランザクションが開始されて
いないのが原因です.

コンストラクタに対しては宣言的トランザクションは
適用できないので,コンストラクタで Hibernate Session を
使用するのをやめるか,手動でトランザクションを開始するか,
j2ee.dicon で allowLocalTx を true にするかしてください.


-- 
<component name="koichik">
    <property name="fullName">"Koichi Kobayashi"</property>
    <property name="email">"[E-MAIL ADDRESS DELETED]"</property>
    <property name="blog">"http://d.hatena.ne.jp/koichik"</property>
</component>



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