PostgreSQL 8.0.0 文書
前のページ | 巻戻し |  | 早送り | 次のページ

# 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`には、`UPDATE`か`DELETE`、あるいはその両方の権限が必要です。

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

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

前のページ | ホーム | 次のページ
LOAD | 上に戻る | MOVE