LOCK TABLES と UNLOCK TABLES 構文

LOCK TABLES
    tbl_name [AS alias]
      {READ [LOCAL] | [LOW_PRIORITY] WRITE}
    [, tbl_name [AS alias]
      {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...
UNLOCK TABLES

LOCK TABLES は、現在のスレッドに対してベース テーブル (ビュー以外) をロックします。もしテーブルが1つでも他のスレッドによってロックされていたら、それは全てのロックを入手するまでブロックします。

UNLOCK TABLES は現在のスレッドによって行われたロックを全て明示的にリリースします。スレッドが別の LOCK TABLES を発行した時、またはサーバへの接続が閉じられた時に、現在のスレッドにロックされている全てのテーブルは暗黙的にロック解除されます。 UNLOCK TABLES はまた、FLUSH TABLES WITH READ LOCK を利用してグローバル リード ロックを取得した後に、そのロックをリリースする為に利用されます。(FLUSH TABLES WITH READ LOCK ステートメントによってリード ロックされている全てのデータベース内の全てのテーブルをロックする事ができます。詳しくは 項2. 「FLUSH 構文」 を参照してください。これは、もし Veritas のような時間内にスナップショットを撮る事ができるファイルシステムを持っていると、バックアップを取るのが大変便利な方法になります。)

LOCK TABLES を利用する為には、関連するテーブルに対して LOCK TABLES 権限と SELECT 権限を持つ必要があります。

LOCK TABLES を利用する主な理由は、テーブルを更新する際にトランザクションをエミュレートしたり、スピードを早くしたりする事です。後ほどもう少し詳しく説明します。

テーブル ロックは、別のクライアントによる不適切な読み込みや書き込みに対してのみ保護します。ロックを保持しているクライアントは、それがリード ロックだとしても、DROP TABLE のようなテーブル レベル操作を行う事ができます。切り捨て操作はトランザクション セーフではないので、もし、アクティブなトランザクションの実行中や、テーブル ロックを保持している最中にクライアントがそれを行おうとすると、エラーが発生します。

LOCK TABLES とトランザクション テーブルを共に利用する際には、次の事に注意してください。

LOCK TABLES を利用する時、ステートメントの中で利用する予定の全てのテーブルをロックしなければいけません。LOCK TABLES はビューをロックしないので、もし今実行している操作がビューを利用するなら、それらのビューが依存する全てのベース テーブルもロックしなければいけません。LOCK TABLES ステートメントで取得したロックが有効な間は、そのステートメントによってロックされていないテーブルにアクセスする事はできません。また、単一クエリの中でロックされたテーブルを複数回使用する事はできません。各エイリアスに対して別々にロックを取得する必要がある場合には、代わりにエイリアスを利用してください。

mysql> LOCK TABLE t WRITE, t AS t1 WRITE;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;

もしステートメントがエイリアスを利用してテーブルを参照するなら、同じエイリアスを利用してテーブルをロックする必要があります。エイリアスを指定しないでテーブルをロックする事はできません。

mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

反対に、もしエイリアスを利用してテーブルをロックすると、そのエイリアスを利用してステートメント内でそのテーブルを参照する必要があります。

mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;

もしスレッドがテーブル上で READ ロックを取得したら、そのスレッド(そしてそれ以外の全てのスレッド)はテーブルからは読み込む事しかできません。もしスレッドがテーブル上で WRITE ロックを取得したら、そのロックを保持するスレッドのみがそのテーブルに書き込みができます。ロックが解除されるまで、その他のスレッドはテーブルの読み込み、書き込みからブロックされます。

READ LOCALREAD の違いは、READ LOCAL は、ロックされている間に非対立 INSERT ステートメント(並列挿入)が実行される事を許容するという事です。しかし、もしロックを保持している間に MySQL の外部でデータベース ファイルを複製しようとすると、これを利用する事はできません。 InnoDB テーブルに対しては、READ LOCALREAD と同じです。

WRITE ロックは通常、更新がなるべく速く行われるよう、READ ロックよりも高い優先順位を持ちます。これは、もし1つのスレッドが READ ロックを取得し、そして別のスレッドが WRITE ロックをリクエストすると、後続の READ ロックリクエストは、WRITE スレッドがロックを得て、それをリリースするまで待つ、という意味になります。WRITE ロックを待っているスレッドの前に、別のスレッドが READ ロックを取得するのを許容する為に、LOW_PRIORITY WRITE を利用する事ができます。READ ロックを持つスレッドが無い時に、時間が残っている事が確実である時だけ、LOW_PRIORITY WRITE ロックを利用しなければいけません。(例外:トランザクション モード(自動コミット = 0)の InnoDB テーブルに対しては、LOW_PRIORITY WRITE ロックは通常の WRITE ロックのように機能し、待機中の READ ロックに先行します。)

LOCK TABLES は次のように機能します。

  1. ロックされる全てのテーブルを内部定義順に並べ替えます。ユーザの立場からは、この順番は定義されていません。

  2. もしそのテーブルが読み込みと書き込みの両方についてロックされるなら、読み込みロックの前に書き込みロックを行ってください。

  3. スレッドが全てのロックを得るまで、テーブル1つずつにロックをして下さい。

.この方法は、テーブル ロックにデッドロックが起きない事を保証します。:しかし、この方法について知っておかなければいけない事があります。もしテーブルに対して LOW_PRIORITY WRITE ロックを利用していたら、MySQL は READ ロックを必要とするスレッドがなくなるまで、この特定のロックを待つ、という意味になります。スレッドが WRITE ロックを得て、ロック テーブル リストの中の次のテーブルのロックを得るのを待っている時、他の全てのスレッドは WRITE ロックが解除されるのを待ちます。もしこれが、ご利用のアプリケーションにとって深刻な問題となってしまったら、いくつかのテーブルをトランザクション セーフ テーブルに変換する事を考慮するべきです。

テーブル ロックを待っているスレッドを終了させる為に、KILL を安全に使用する事ができます。詳しくは 項3. 「KILL 構文」 を参照してください。

INSERT が別のスレッドによって実行されてしまう為、INSERT DELAYED と共に利用しているテーブルをロック してはいけない という事に注意してください。

通常、全ての単一 UPDATE ステートメントはアトミックなので、テーブルをロックする必要はありません。別のスレッドが現在実行中の SQL ステートメントの邪魔をする事はできません。しかし、テーブルをロックする事が利益をもたらす場合もいくつかあります。

多くの場合、相対更新(UPDATE customer SET value=value+new_value)または LAST_INSERT_ID() 関数を利用する事で、LOCK TABLES の利用を避ける事ができます。詳しくは 項3. 「トランザクションとアトミックオペレーション」 を参照してください。

ユーザ レベルの通知ロック機能 GET_LOCK()RELEASE_LOCK() を利用する事で、テーブルのロックを避ける事ができる場合があります。これらのロックははサーバ内のハッシュ テーブルの中に保存され、スピードを速くする目的で pthread_mutex_lock()pthread_mutex_unlock() を利用して実施されます。詳しくは 項 「その他の関数」 を参照してください。

ロックの規定に関しての更なる情報は 項 「MySQL のテーブルロック方法」 を参照してください。

注意:もしロックされたテーブル上に ALTER TABLE を利用すると、ロックが解除される可能性があります。詳しくは 項B. 「Problems with ALTER TABLE」 を参照してください。