LOCK

名前

LOCK -- テーブルのロック

概要

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

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

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

説明

LOCK TABLE はテーブルレベルのロックを獲得し、必要であれば競合するロックが解除されるのを待ちます。 ロックは、一度取得されると現行のトランザクションが完了するまで保持されます。 (UNLOCK TABLE コマンドはありません。ロックはトランザクションの終了時に常に解除されます。)

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

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

このようなトランザクションでテーブル内データを変更する場合は、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 a; LOCK b; と同じです。 テーブルは1つ1つLOCKで指定された順番でロックされます。

lockmode

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

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

注釈

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

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

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

外部キーテーブルへの挿入を行なう際に、プライマリキーテーブルへの 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 のものと互換性があります。