試してみてください。開いpsql
てセットアップを行います。
CREATE TABLE foo_bar(id integer primary key);
CREATE TABLE spam_eggs(
foo_bar_id integer not null references foo_bar(id) on delete cascade
);
INSERT INTO foo_bar (id) VALUES (1),(2),(3),(4);
INSERT INTO spam_eggs(foo_bar_id) VALUES (1),(2),(3),(4);
次に、別のpsql接続を開きます。BEGIN
それらの両方でのトランザクション。
- 最初の(古い)セッションで、
SELECT 1 FROM spam_eggs WHERE foo_bar_id = 4 FOR UPDATE;
- 2番目の(新しい)セッションで、
DELETE FROM foo_bar WHERE id = 4;
2番目のステートメントが最初のステートメントでブロックされていることがわかります。これは、DELETE
onが外部キー参照にfoo_bar
カスケードしspam_eggs
て行をロックしようとし、それを削除できるようにするためです。そのロックは、によって保持されているロックをブロックしますSELECT ... FOR SHARE
。
一般に、これらすべての状況でテストしてみてください。
- txは
BEGIN ISOLATION LEVEL READ COMMITTED
、最初に発行されます。ROLLBACK
- txは
BEGIN ISOLATION LEVEL READ COMMITTED
、最初に発行されます。COMMIT
- txは
BEGIN ISOLATION LEVEL SERIALIZABLE
、最初に発行されます。ROLLBACK
- txは
BEGIN ISOLATION LEVEL SERIALIZABLE
、最初に発行されます。COMMIT
あなたが何を期待するかを知っていることを確認するために。それをテストする前にあなたが起こると予想することを通して推論するならば、それはあなたの学習にも良いです。
この場合、READ COMMITTED
とSERIALIZABLE
分離レベルは同じように動作します。ただし、実際にUPDATE
アフターを実行するSELECT ... FOR UPDATE
とCOMMIT
、動作が異なります。READ COMMITTED
バージョンはDELETE
正常に実行されますが、バージョンSERIALIZABLE
は次のように失敗します。
regress=# BEGIN ISOLATION LEVEL SERIALIZABLE;
regress=# DELETE FROM foo_bar WHERE id = 4;
ERROR: could not serialize access due to concurrent update
CONTEXT: SQL statement "DELETE FROM ONLY "public"."spam_eggs" WHERE $1 OPERATOR(pg_catalog.=) "foo_bar_id""