[Seasar-user:11393] Re: [Kuina-Dao] dao.persist(entity) で,主キー重複エラーを回避するには?

Koichi Kobayashi [E-MAIL ADDRESS DELETED]
2007年 11月 1日 (木) 19:00:36 JST


小林 (koichik) です.

Date:    Thu, 01 Nov 2007 18:10:12 +0900
From:    "Applied_MATSUDA Masaaki" <[E-MAIL ADDRESS DELETED]>
To:       <[E-MAIL ADDRESS DELETED]>
Subject: [Seasar-user:11391] [Kuina-Dao] dao.persist(entity) で,主キー重複エラーを回避するには?

> Serviceクラスのコードではこのようなことをやっています.
> 
> synchronized public void insertOrUpdate(String code, Integer yyy) {
>   Fuga fuga = new Fuga();
>   fuga.setCode(code); // 主キーなんですよこれが.
>   fuga.setXXX(Boolean.TRUE);
>   fuga.setYYY(yyy);
>   dao.persist(fuga);
> }
> 
> codeが主キーなんですけれど,
> updateしたくて,レコード上に既にある"1"とかを指定して
> 実行すると上記のどっかんです.

JAP の persist() は INSERT 相当なのでそうなります.
INSERT OR UPDATE 相当の機能はありません.

public void insertOrUpdate(String code, Integer yyy) {
  Fuga fuga = dao.find(code);
  if (fuga == null) {
    fuga = new Fuga();
    fuga.setCode(code);
    fuga.setXXX(Boolean.TRUE);
    fuga.setYYY(yyy);
    dao.persist(fuga);
  } else {
    fuga.setXXX(Boolean.TRUE);
    fuga.setYYY(yyy);
  }
}

のようにしてください.

ただし,同じタイミングで別のトランザクションが
同じ主キーを持つオブジェクトを persist() すると
どちらかが例外になります.
そのタイミングは persist() の時とは限らず,
トランザクションをコミットする時になる場合も
あります.
# このケースではコミット時になるはず.

どう対処するかは要件およびトランザクション境界を
どう設定するかにもよるので一概には言えません.

この insertOrUpdate() メソッドだけ requiresNew で
実行して,その外側で例外をキャッチした場合は
もう一度 insertOrUpdate() を実行する (今度は
find() が null を返さないので成功するはず) などの
方法があります.
その場合は外側のトランザクションをロールバック
しても INSERT/UPDATE が取り消せなくなるので
注意が必要です.

なお,上記のメソッドに synchronized が
付いていますが,DB アクセスに関して
synchronized で排他制御しても,ほとんどの
場合は無力ではないかと思います.


--
<signature>
   <name>Koichi Kobayashi</name>
   <e-mail>[E-MAIL ADDRESS DELETED]</e-mail>
</signature>




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