あなたが説明する振る舞いは正常であり、どのトランザクションリレーショナルデータベースでも予想されます。
PostgreSQLがedited
の値を表示した場合 最初のSELECT
そうするのは間違っているでしょう-それは「ダーティリード」と呼ばれ、データベースでは悪いニュースです。
PostgreSQLはSELECT
で待機することが許可されます コミットまたはロールバックするまで、ただしSQL標準では必須ではなく、待機するように指示しておらず、技術的な理由で待機する必要もないため、要求したデータが返されます。すぐに。結局のところ、コミットされるまで、そのupdate
ある種のものだけが存在します-それはまだ起こるかもしれないし、起こらないかもしれません。
PostgreSQLが常にここで待機していると、データベースに対して一度に1つの接続しか実行できないという状況にすぐに遭遇します。パフォーマンスにはあまり良くなく、ほとんどの場合まったく不要です。
同時のUPDATE
を待ちたい場合 (またはDELETE
)、SELECT ... FOR SHARE
を使用します 。 (ただし、これはINSERT
では機能しないことに注意してください 。
詳細:
SELECT
FOR UPDATE
なし またはFOR SHARE
句は行レベルのロックを取りません。したがって、現在コミットされている行が何であるかを確認し、その行を変更する可能性のある実行中のトランザクションの影響を受けません。概念は、ドキュメントのMVCCセクション
で説明されています。 。一般的な考え方は、PostgreSQLはコピーオンライトであり、トランザクションまたはステートメントが開始時に「見る」ことができたもの、つまりPostgreSQLが「スナップショット」と呼ぶものに基づいて正しいコピーを返すことができるバージョン管理を備えているというものです。
デフォルトのREAD COMMITTED
分離スナップショットはステートメントレベルで取得されるため、SELECT
行、COMMIT
別のトランザクションからの変更、およびSELECT
ここでも、1回のトランザクション内でも異なる値が表示されます。 SNAPSHOT
を使用できます トランザクションの開始後にコミットされた変更を確認したくない場合は分離、またはSERIALIZABLE
特定の種類のトランザクションの相互依存性に対する保護をさらに強化するための分離。
ドキュメントの
SELECT
が必要な場合 進行中のトランザクションが選択されている行への変更をコミットまたはロールバックするのを待つには、SELECT ... FOR SHARE
を使用する必要があります 。これにより、UPDATE
によって取得されたロックがブロックされます またはDELETE
ロックを取得したトランザクションがロールバックまたはコミットするまで。
INSERT
ただし、違います。タプルは、コミットするまで他のトランザクションには存在しません。同時INSERT
を待つ唯一の方法 sはEXCLUSIVE
を取ることです テーブルレベルのロック。これにより、テーブルを読んでいる間、他の誰もテーブルを変更していないことがわかります。通常、これを行う必要があるということは、アプリケーションに設計上の問題があることを意味します。ただし、アプリは気にしないでください コミットされていないinsert
がある場合 まだ飛行中です。
ドキュメントの明示的なロックの章 を参照してください。 。