2

私のテーブルには、md5というラベルの付いた2次一意キーがあります。挿入する前に、MD5が存在するかどうかを確認し、存在しない場合は、以下に示すように挿入します。

-- Attempt to find this item
SELECT INTO oResults (SELECT domain_id FROM db.domains WHERE "md5"=oMD5);

IF (oResults IS NULL) THEN

    -- Attempt to find this domain
    INSERT INTO db.domains ("md5", "domain", "inserted") 
        VALUES (oMD5, oDomain, now());

    RETURN currval('db.domains_seq');

  END IF;

これはシングルスレッドの挿入に最適です。私の問題は、同じMD5を持つ2つの外部アプリケーションが同時に関数を呼び出す場合です。私は次のような状況に陥ります:

アプリ1:MD5が存在しないことを確認します

アプリ2:このMD5をテーブルに挿入します

アプリ1:MD5が存在しないと判断したため、テーブルにMD5を挿入しますが、MD5が存在しないことを確認した直後に、アプリ2が挿入したためエラーが発生します。

これを行うためのより効果的な方法はありますか?

挿入時にエラーをキャッチできますか?その場合は、domain_idを選択しますか?

前もって感謝します!


これは、PostgreSQLでの重複更新に関するInsertでもカバーされているようです。

4

1 に答える 1

2

「一意の制約違反」エラーが発生した場合は、それを無視して続行し、他のエラーが発生した場合は救済します。そうすれば、重複チェックをデータベースに直接プッシュすることができ、競合状態は解消されます。

このようなもの:

  • MD5 値の挿入を試みます。
    • 固有の違反エラーが発生した場合は、無視して続行してください。
    • 他のエラーが発生した場合は、救済して文句を言います。
    • エラーが発生しない場合は、続行します。
  • SELECT INTO oResults (SELECT domain_id FROM db.domains WHERE "md5"=oMD5)を抽出してくださいdomain_id

パフォーマンスが少し低下する可能性がありますが、「高速だが壊れている」よりも「正確で少し遅い」の方が優れています。

最終的には、成功した挿入よりも多くの例外が発生する可能性があります。次に、(外部キーを介して) 参照をテーブルに挿入し、db.domainsそこに FK 違反をトラップすることができます。FK違反があった場合は、古い「挿入して一意の違反を無視する」db.domainsを実行してから、FK違反を引き起こした挿入を再試行してください。これは基本的な考え方と同じです。例外をスローする可能性が最も低いものを選択して、それに従うだけです。

于 2011-07-21T06:03:43.637 に答える