0

テーブルの次のキーの値を取得するためにデータベースシーケンスを使用することになっていることは知っていますが(単一列の数値主キーを想定してみましょう)、シーケンスが使用されていない場合、明らかなコードのにおいがしますか?次のコード (コードは JPA の Java ですが、パターンは実際には言語とテクノロジに依存しません):

  boolean haveSucceeded = false;
  int _i = 0 ;
  while ((!haveSucceeded) && (_i++ < MAX_RETRIES)) {
     try {
          user.setId(getFacade().maxId()+1); // line A
          getFacade().create(user);          // line B
          haveSucceeded = true;
     } catch (javax.ejb.EJBTransactionRolledbackException exc) {
          debug("ConstraintValidationException, "+ ( (_i<MAX_RETRIES)?"retrying":"giving up"));
     }
  }

同時アクセス (他のアプリケーション インスタンスからの可能性もある) による衝突の可能性を考慮して再試行が行われ、行 A (最大値が計算される場所) と行 B (行が挿入される場所) が同じデータを操作します。

4

2 に答える 2

2

これはスレッドセーフではないようです。スレッドセーフな方法で次のことを行う必要があります。

  • ユーザーテーブルをロックする
  • 現在の max(id) を読む
  • 1 を追加し、それを次の ID として使用します
  • テーブルのロックを解除

これは、自動インクリメントを使用してデータベースで何が起こるかを概算します。

テーブルをロックできない場合は、メソッドを作成するかロック オブジェクトstatic synchronizedを使用して、メソッドを同期します。static

 private static final Object lock = new Object();

 void yourMethod() {
     synchronized (lock) {
         // your code here
     }
 }

サーバーの複数のインスタンスを実行している場合、このアプローチでは不十分です。

于 2012-08-21T19:48:04.603 に答える
-1

わざわざ access で再試行する場合は、Statement を作成するときに「メソッド」を CONCUR_READ_ONLY または CONCUR_UPDATABLE インターフェイス「Connection」.createStatement() で設定してみませんか。ほとんどの場合、データベース自体が読み取りの同時実行を制御しますが、接続はクエリの一部としてデータベースに読み取り方法を伝えることができます。アクセスの問題例外が同時実行性の読み取りに関する問題よりも発生する可能性が高い場合に、なぜループを気にする必要があるのか​​ わかりません。ユーザーを作成している場合、データ値をそれほど無差別にしたい理由を理解できません。最初にユーザーの存在を確認してから、プロセスを中止し、意図した新しいユーザーにメッセージを送り返す必要があります「別のユーザー名を選択してください」など。

于 2012-08-21T20:07:14.170 に答える