PostgreSQLからドメインモデルデータを取得するために、テーブルではなくビューを選択する場合があります。これを行うのは、複数のクエリを実行してすべてのリレーショナル依存関係を解決するのではなく、1つのクエリでできるだけ多くの情報を返すことができるようにするためです。これは主に、テーブル間に1対1の関係があるか、テーブルがルックアップテーブルであり、特定の列が必要なためなどです。特定の競合状態を防ぐために、私が使用している戦略の1つはSELECT ... FOR SHARE/UPDATE
クエリ。これらをビューに対して使用し始めたとき、これらがどのように動作するのか疑問に思っています。
2つのテーブルA
とB
があり、それぞれに列ID
があるとします。ここで、これら2つのテーブル間の結合操作であるビューAB
があるとします。これがデカルト結合であるとしましょう:
SELECT
"A"."ID" AS "AID",
"B"."ID" AS "BID"
FROM "A"
CROSS JOIN "B"
もし私たちがSELECT FOR UPDATE
に対してAB
に対して、どのテーブルのどの行が次のインスタンスでロックされるのですか?
SELECT * FROM "AB" WHERE "AB"."AID" = :ID
SELECT * FROM "AB" WHERE "AB"."BID" = :ID
SELECT * FROM "AB" WHERE "AB"."AID" = :ID1 AND "AB"."BID" = :ID2
次の行は、3つのケースで更新のためにロックされます。
結果は、このステートメントを ドキュメント: で読んだ後に期待できるとおりです。
ロック句がビューまたはサブクエリに適用される場合、それはビューまたはサブクエリで使用されるすべてのテーブルに影響します。
拡張機能 pgrowlocks。 をインストールします。
create extension if not exists pgrowlocks;
Psqlの2つのインスタンスを実行します。最初にトランザクションを開始し、クエリを実行します。
psql#1:
begin;
select *
from "AB"
where "AID" = 3 and "BID" = 103
for update;
Psqlの他のインスタンスでロックされた行を確認できます。
psql#2:
select * from pgrowlocks('"B"');
locked_row | locker | multi | xids | modes | pids
------------+--------+-------+---------+----------------+--------
(0,4) | 88577 | f | {88577} | {"For Update"} | {8068}
(1 row)
最後に(次のテストの前に)トランザクションを閉じることを忘れないでください。
psql#1:
rollback;
上記の結果の最初の列はctid
です。クエリで元の行を選択できます。
select *
from "B"
where ctid = '(0,4)';