★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

LOCK

名前

LOCK -- テーブルのロック

概要

LOCK [ TABLE ] name [, ...] [ IN lockmode MODE ] [ NOWAIT ]

ここでlockmodeは以下のいずれかです。

    ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
    | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE

説明

LOCK TABLEはテーブルレベルのロックを獲得し、必要であれば競合するロックが解除されるまで待機します。 NOWAITが指定された場合、LOCK TABLEは対象のロックが獲得できるまで待機しません。 すぐに獲得できなければ、このコマンドを中止し、エラーを出力します。 ロックは、一度取得されると現行のトランザクションが完了するまで保持されます。 (UNLOCK TABLEといったコマンドはありません。 ロックはトランザクションの終了時に常に解除されます。)

テーブルを参照するコマンドのために自動的にロックを獲得する場合、PostgreSQLは常に使用可能な一番弱いロックモードを使用します。 LOCK TABLEはより制限の強いロックが必要な場合のために用意されています。 例えば、アプリケーションが隔離レベルREAD COMMITTEDでトランザクションを実行し、そのトランザクションの期間中テーブルのデータの安定性を確実にする必要がある場合を考えてみます。 これを達成するために、問い合わせ実行前にテーブル全体にSHAREロックモードを使用することができます。 これにより、データが同時に変更されるのを防ぎ、それ以降のテーブルの読み取りを安定させることができます。 なぜならSHAREロックモードは書き込み側が獲得するROW EXCLUSIVEロックと競合するのでLOCK TABLE name IN SHARE MODE文は、ROW EXCLUSIVEの同時保持者全てのコミットまたはロールバックするのを待つからです。 このように、一度ロックを獲得すると、コミットされていない状態の書き込みはなくなり、ユーザがロックを解除するまで誰も書き込みを開始することはできません。

シリアライザブル隔離レベルでのトランザクション実行中にこれと同様の効果を得るには、全てのSELECT文とデータ更新用の文を実行する前にLOCK TABLE文を実行する必要があります。 シリアライザブルなトランザクション側から参照するデータの状態は、最初のSELECT文またはデータ更新用文が開始された時点で固定されます。 トランザクション内で後でLOCK TABLEを行っても同時書き込みを防ぎますが、トランザクションの読み込み対象のデータがコミットされた最新の値に対応しているかは保証されません。

このようなトランザクションでテーブル内データを変更する場合は、SHAREモードではなくSHARE ROW EXCLUSIVEロックモードを使用する必要があります。 これによって、この種のトランザクションが同時に複数実行されることがなくなります。 SHARE ROW EXCLUSIVEを使用しないと、デッドロックが発生する可能性があります。 つまり、2つのトランザクションの両方がSHAREモードを獲得したものの、実際に更新を行うためのROW EXCLUSIVEモードを獲得することができないような状態になる可能性があります。 (トランザクション自身のロックは競合しないので、トランザクションはSHAREモードを保持している時にROW EXCLUSIVEを獲得することができます。 しかし、他のトランザクションがSHAREモードを保持している時にはROW EXCLUSIVEを獲得することはできません。) デッドロックを回避するために、確実に全てのトランザクションは同一オブジェクトに対して同一の順番でロックを取得してください。 また、1つのオブジェクトに対して複数のロックモードを呼び出す場合、トランザクションは常に最も制限の強いモードを最初に取得しなければなりません。

ロックモードとロック取得方針についてのより詳細については項12.3を参照してください。

パラメータ

name

ロックする既存のテーブルの名前です (スキーマ修飾名でも可)。

LOCK a, b;というコマンドはLOCK TABLE a; LOCK TABLE b;と同じです。 テーブルは1つ1つLOCKで指定された順番でロックされます。

lockmode

このロックモードで、取得するロックが競合するロックが何かを規定します。 ロックモードについては、項12.3で説明します。

ロックモードを指定しない場合、もっとも制限が強いACCESS EXCLUSIVEが使用されます。

NOWAIT

LOCK TABLEが競合するロックの開放を待機してはならないことを指定します。 指定したロック(複数可)を待機することなく、すぐに獲得できない場合、トランザクションはアボートします。

注釈

LOCK TABLE ... IN ACCESS SHARE MODEには、対象テーブルのSELECT権限が必要です。 他の形式のLOCKには、UPDATEDELETE、あるいはその両方の権限が必要です。

LOCK TABLEはトランザクションブロック内部(BEGIN/COMMITの組合せ)でのみ有効です。 従って、トランザクションが終了するとロックも削除されます。 トランザクションブロックの外部のLOCK TABLEコマンドはそのコマンドのみのトランザクションを形成しますので、このロックは取得後すぐに削除されます。

LOCKはテーブルレベルのロックのみを扱います。 そのため、モード名にROWが含まれるのは適切ではありません。 これらのモード名によって、ロックされたテーブル内での行レベルのロックを獲得しようとしていると、通常は解釈されてしまうでしょう。 また、ROW EXCLUSIVEモードは共有可能なロックです。 LOCK TABLEに関しては、全てのロックモードが同じ意味を持っていることに注意してください。 違うのは、どのモードがどのモードと競合するかという規則だけです。 実際の行レベルロックの獲得方法についてはSELECTマニュアルページの項12.3.2FOR UPDATEを参照してください。

外部キーテーブルへの挿入を行なう際に、プライマリキーテーブルへのSHAREロックを獲得します。

BEGIN WORK;
LOCK TABLE films IN SHARE MODE;
SELECT id FROM films 
    WHERE name = 'Star Wars: Episode I - The Phantom Menace';
-- レコードがなければROLLBACKしてください。
INSERT INTO films_user_comments VALUES 
    (_id_, 'GREAT! I was waiting for it for so long!');
COMMIT WORK;

削除操作を行なう際にプライマリキーテーブルのSHARE ROW EXCLUSIVEロックを取得します。

BEGIN WORK;
LOCK TABLE films IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM films_user_comments WHERE id IN
    (SELECT id FROM films WHERE rating < 5);
DELETE FROM films WHERE rating < 5;
COMMIT WORK;

互換性

標準SQLにはLOCK TABLEはありません。 その代わりにトランザクションの同時性レベルを指定するSET TRANSACTIONを使用します。 PostgreSQLはこれもサポートしています。 詳細はSET TRANSACTIONを参照してください。

ACCESS SHAREACCESS EXCLUSIVESHARE UPDATE EXCLUSIVEロックモードを除き、PostgreSQLのロックモードとLOCK TABLE構文はOracleのものと互換性があります。