SERIALIZABLE
をリクエストするたびに 分離DBは、クエリの同時セットをシリアルに実行されたように見えるように試みます。 彼らが生み出す結果の観点から。これは常に可能であるとは限りません。 2つのトランザクションに相互依存関係がある場合。この場合、PostgreSQLはトランザクションの1つを中止します シリアル化失敗エラーが発生し、再試行する必要があることを通知します。
SERIALIZABLE
を使用するコード トランザクションを再試行する準備を常にする必要があります。 SQLSTATE
をチェックする必要があります シリアル化に失敗した場合は、トランザクションを繰り返します。
トランザクション分離ドキュメント を参照してください。 。
この場合、あなたの主な誤解は次のようなものだと思います。
それはそのようなものではないので、INSERT ... SELECT
です。 vo_business.repositoryoperation
に触れる 読み取りと書き込みの両方に。これは、同じことを行う別のトランザクション、または別の方法でテーブルの読み取りと書き込みを行うトランザクションとの潜在的な依存関係を作成するのに十分です。
さらに、シリアル化可能な分離コードは、状況によっては、効率上の理由から、ブロックレベルの依存関係情報を保持するように縮退する可能性があります。したがって、特に負荷がかかっている場合は、必ずしも同じ行、同じストレージブロックにアクセスするトランザクションであるとは限りません。
PostgreSQLは、安全かどうかわからない場合、シリアル化可能なトランザクションを中止することを好みます。プルーフシステムには制限があります。したがって、それをだますケースを見つけた可能性もあります。
確実に知るには、両方のトランザクションを並べて表示する必要がありますが、これはinsert ... select
を示す証明です。 自分自身と衝突する可能性があります。 3つのpsql
を開きます セッションと実行:
session0: CREATE TABLE serialdemo(x integer, y integer);
session0: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
session0: LOCK TABLE serialdemo IN ACCESS EXCLUSIVE MODE;
session1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
session2: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
session1: INSERT INTO serialdemo (x, y)
SELECT 1, 2
WHERE NOT EXISTS (SELECT 1 FROM serialdemo WHERE x = 1);
session2: INSERT INTO serialdemo (x, y)
SELECT 1, 2
WHERE NOT EXISTS (SELECT 1 FROM serialdemo WHERE x = 1);
session0: ROLLBACK;
session1: COMMIT;
session2: COMMIT;
session1は正常にコミットします。 session2は次の場合に失敗します:
ERROR: could not serialize access due to read/write dependencies among transactions
DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt.
HINT: The transaction might succeed if retried.
これはあなたの場合と同じシリアル化の失敗ではなく、あなたの ステートメントは互いに競合する可能性がありますが、insert ... select
であることを示しています。 思ったほどアトミックではありません。