FOR SHARE句、SKIP LOCKED句、NOWAITオプション、SELECT ... FOR UPDATEの使い方
PostgreSQLでロックされていない行を選択する
FOR SHARE
句は、SELECT
クエリが実行される際に、選択された行が他のセッションによって更新されないようにロックします。ただし、他のセッションはロックされている行を読み出すことはできます。
SELECT * FROM table FOR SHARE;
SKIP LOCKED
句は、SELECT
クエリが実行される際に、すでに他のセッションによってロックされている行をスキップします。
SELECT * FROM table SKIP LOCKED;
NOWAIT
オプションは、SELECT
クエリが実行される際に、ロックを取得できない場合はすぐにエラーを返すように指定します。
SELECT * FROM table FOR SHARE NOWAIT;
SELECT ... FOR UPDATE
は、SELECT
クエリが実行される際に、選択された行を排他ロックします。他のセッションは、ロックされている行を読み出すことも更新することもできません。
SELECT * FROM table FOR UPDATE;
- 他のセッションがロックされている行を読み出すことを許可したい場合は、
FOR SHARE
句を使う。 - ロックされている行をスキップしたい場合は、
SKIP LOCKED
句を使う。 - ロックを取得できない場合はすぐにエラーを返したい場合は、
NOWAIT
オプションを使う。 - 選択された行を排他ロックしたい場合は、
SELECT ... FOR UPDATE
を使う。
注意点
FOR SHARE
句とSKIP LOCKED
句は、同時に使用することはできません。NOWAIT
オプションは、FOR SHARE
句とSELECT ... FOR UPDATE
と一緒に使用することができます。SELECT ... FOR UPDATE
は、トランザクション内で実行する必要があります。
-- FOR SHARE句
SELECT * FROM table FOR SHARE;
-- SKIP LOCKED句
SELECT * FROM table SKIP LOCKED;
-- NOWAITオプション
SELECT * FROM table FOR SHARE NOWAIT;
-- SELECT ... FOR UPDATE
BEGIN;
SELECT * FROM table FOR UPDATE;
-- ...
COMMIT;
このサンプルコードは、PostgreSQLの公式ドキュメントやQiitaなどの記事を参考に作成しています。
注意
サンプルコードを実行する前に、PostgreSQLのバージョンと設定を確認してください。
PostgreSQLでロックについて詳しく知りたい場合は、PostgreSQL公式ドキュメントの「明示的ロック」を参照してください。
PostgreSQLでロックされていない行を選択するその他の方法
SELECT ... WHERE NOT EXISTS (SELECT ...)を使う
SELECT * FROM table
WHERE NOT EXISTS (
SELECT * FROM table
WHERE id = 1
FOR UPDATE
);
アドバンストロックを使う
PostgreSQL 9.5以降では、アドバンストロックを使用することができます。アドバンストロックは、より細かいロック制御が可能で、ロックされていない行を選択する際に役立ちます。
SELECT * FROM table
WHERE xmin < pg_backend_pid();
アプリケーションロジックで処理する方法もあります。例えば、以下のような方法が考えられます。
- ロックを取得する前に、行がロックされているかどうかを確認する。
- ロックを取得できない場合は、一定時間待ってから再試行する。
- ロックを取得できない場合は、別の行を選択する。
- 他のセッションがロックされている行を読み出すことを許可したい場合は、
SELECT ... WHERE NOT EXISTS (SELECT ...)
を使う。 - より細かいロック制御が必要な場合は、アドバンストロックを使う。
- アプリケーションロジックで処理するのが簡単な場合は、アプリケーションロジックで処理する。
postgresql locking