0

与えられた:

customer[id BIGINT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(30), count INT]

以下をアトミックに実行したいと思います: 顧客が既に存在する場合は更新します。それ以外の場合は、新しい顧客を挿入します。

理論的には、これはSQL-MERGEに完全に適合するように思えますが、私が使用しているデータベースはAUTO_INCREMENT 列を使用した MERGE をサポートしていません。

https://stackoverflow.com/a/1727788/14731は、存在しない行に対してクエリまたは更新ステートメントを実行すると、データベースがインデックスをロックして同時挿入を防止することを示しているようです。

この動作は SQL 標準で保証されていますか? このように動作しないデータベースはありますか?

更新: 申し訳ありませんが、これについては以前に言及する必要がありました: 解決策は、それが不可能でない限り、READ_COMMITTED トランザクション分離を使用する必要があります。その場合、SERIALIZABLE の使用を受け入れます。

4

4 に答える 4

2

このトピックに関して多くの混乱があるように思われるので、私自身の質問に答えます。のようだ:

-- BAD! DO NOT DO THIS! --
insert customer (email, count) 
select 'foo@example.com', 0
where not exists (
      select 1 from customer
      where email = 'foo@example.com'
)

競合状態が発生する可能性があります (行が存在しない場合のみ行を挿入するを参照してください)。私が収集できたものから、この問題に対する唯一の移植可能な解決策は次のとおりです。

  1. マージするキーを選択します。これは主キーまたは別の一意のキーである可能性がありますが、一意の制約が必要です。
  2. insert新しい行を試してください。行が既に存在する場合に発生するエラーをキャッチする必要があります。
  3. 難しい部分は終わりました。この時点で、行が存在することが保証され、書き込みロックを保持しているという事実によって競合状態から保護されます (insert前の手順の による)。
  4. 先に進みupdate、必要に応じて、またはselectその主キー。
于 2013-09-16T03:05:48.160 に答える