LOCK TABLEStbl_name
[ASalias
] {READ [LOCAL] | [LOW_PRIORITY] WRITE} [,tbl_name
[ASalias
] {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
ステートメントによってリード
ロックされている全てのデータベース内の全てのテーブルをロックする事ができます。詳しくは
項12.5.5.2. 「FLUSH
構文」
を参照してください。これは、もし Veritas
のような時間内にスナップショットを撮る事ができるファイルシステムを持っていると、バックアップを取るのが大変便利な方法になります。)
LOCK TABLES
を利用する為には、関連するテーブルに対して
LOCK TABLES
権限と
SELECT
権限を持つ必要があります。
LOCK TABLES
を利用する主な理由は、テーブルを更新する際にトランザクションをエミュレートしたり、スピードを早くしたりする事です。後ほどもう少し詳しく説明します。
テーブル
ロックは、別のクライアントによる不適切な読み込みや書き込みに対してのみ保護します。ロックを保持しているクライアントは、それがリード
ロックだとしても、DROP TABLE
のようなテーブル
レベル操作を行う事ができます。切り捨て操作はトランザクション
セーフではないので、もし、アクティブなトランザクションの実行中や、テーブル
ロックを保持している最中にクライアントがそれを行おうとすると、エラーが発生します。
LOCK TABLES
とトランザクション
テーブルを共に利用する際には、次の事に注意してください。
LOCK TABLES
はトランザクション
セーフではないので、テーブルをロックしようとする前に、全てのアクティブなトランザクションを暗黙的にコミットします。また、トランザクションの開始をすると(例えば
START TRANSACTION
を利用して)、明示的に UNLOCK
TABLES
を実行します。(詳しくは
項12.4.3. 「暗黙のコミットを引き起こすステートメント」
を参照してください。)
LOCK TABLES
を InnoDB
のようなトランザクション
テーブルと共に利用する正しい方法は、AUTOCOMMIT
= 0
を設定し、トランザクションを明示的にコミットするまでは
UNLOCK TABLES
をコールしないという方法です。LOCK
TABLES
をコールする時、InnoDB
は内部的にそれ自身のテーブル
ロックを取り、そして MySQL
もそれ自身のテーブル
ロックを取ります。InnoDB
は次のコミットでテーブル
ロックを解除しますが、MySQL がそのテーブル
ロックを解除するには、 UNLOCK
TABLES
をコールする必要があります。InnoDB
は LOCK TABLES
のコールの後そのテーブル
ロックを即座にリリースし、その為にデッドロックが簡単に起きてしまうので、AUTOCOMMIT
= 1
を持つべきでは有りません。もし
AUTOCOMMIT=1
であれば、古いアプリケーションの不必要なデッドロックを防ぐ為に、InnoDB
テーブル
ロックを全く取得しないという事に注意してください。
ROLLBACK
は MySQL
の非トランザクション テーブル
ロックを解除しません。
FLUSH TABLES WITH READ LOCK
は、グローバル リード
ロックは取得しますがテーブル
ロックはしないので、テーブル
ロックと暗黙的なコミットに関しては
LOCK TABLES
と UNLOCK
TABLES
と同じような動作の制約は受けません。詳しくは
項12.5.5.2. 「FLUSH
構文」 を参照してください。
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 LOCAL
と READ
の違いは、READ LOCAL
は、ロックされている間に非対立
INSERT
ステートメント(並列挿入)が実行される事を許容するという事です。しかし、もしロックを保持している間に
MySQL の外部でデータベース
ファイルを複製しようとすると、これを利用する事はできません。
InnoDB
テーブルに対しては、READ LOCAL
は
READ
と同じです。
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つずつにロックをして下さい。
.この方法は、テーブル
ロックにデッドロックが起きない事を保証します。:しかし、この方法について知っておかなければいけない事があります。もしテーブルに対して
LOW_PRIORITY WRITE
ロックを利用していたら、MySQL は
READ
ロックを必要とするスレッドがなくなるまで、この特定のロックを待つ、という意味になります。スレッドが
WRITE
ロックを得て、ロック
テーブル
リストの中の次のテーブルのロックを得るのを待っている時、他の全てのスレッドは
WRITE
ロックが解除されるのを待ちます。もしこれが、ご利用のアプリケーションにとって深刻な問題となってしまったら、いくつかのテーブルをトランザクション
セーフ
テーブルに変換する事を考慮するべきです。
テーブル
ロックを待っているスレッドを終了させる為に、KILL
を安全に使用する事ができます。詳しくは
項12.5.5.3. 「KILL
構文」 を参照してください。
INSERT
が別のスレッドによって実行されてしまう為、INSERT
DELAYED
と共に利用しているテーブルをロック
してはいけない
という事に注意してください。
通常、全ての単一 UPDATE
ステートメントはアトミックなので、テーブルをロックする必要はありません。別のスレッドが現在実行中の
SQL
ステートメントの邪魔をする事はできません。しかし、テーブルをロックする事が利益をもたらす場合もいくつかあります。
MyISAM
テーブル
セット上でたくさんの操作を行おうとしているのであれば、利用する予定のテーブルをロックしたほうが操作が速くできます。UNLOCK
TABLES
がコールされるまで、MySQL
はロックされたテーブルのキー
キャッシュをフラッシュしないので、MyISAM
テーブルをロックすると、挿入、更新、削除のスピードを速くします。通常、キー
キャッシュは各 SQL
ステートメントの後でフラッシュされます。
テーブルをロックする事のマイナス面は、READ
ロックされたテーブル(ロックを保持している物も含む)を更新できるスレッドが無く、またロックを保持しているテーブル以外は
WRITE
ロックされたテーブルにアクセスできるスレッドが無いという事です。
非トランザクション ストレージ
エンジンに対してテーブルを利用している場合に、もし
SELECT
と UPDATE
の間に別のスレッドがテーブルを変更しない事を保証したければ、LOCK
TABLES
を利用する必要があります。ここに表されている例は、安全に実行する為に
LOCK TABLES
を必要とします。
LOCK TABLES trans READ, customer WRITE; SELECT SUM(value) FROM trans WHERE customer_id=some_id
; UPDATE customer SET total_value=sum_from_previous_statement
WHERE customer_id=some_id
; UNLOCK TABLES;
LOCK TABLES
無しで、別のスレッドが SELECT
と UPDATE
ステートメントの実行の間に、trans
テーブル内に新しい行を挿入する事が可能です。
多くの場合、相対更新(UPDATE customer SET
)または
value
=value
+new_value
LAST_INSERT_ID()
関数を利用する事で、LOCK TABLES
の利用を避ける事ができます。詳しくは
項1.8.5.3. 「トランザクションとアトミックオペレーション」
を参照してください。
ユーザ レベルの通知ロック機能
GET_LOCK()
と
RELEASE_LOCK()
を利用する事で、テーブルのロックを避ける事ができる場合があります。これらのロックははサーバ内のハッシュ
テーブルの中に保存され、スピードを速くする目的で
pthread_mutex_lock()
と
pthread_mutex_unlock()
を利用して実施されます。詳しくは
項11.10.4. 「その他の関数」
を参照してください。
ロックの規定に関しての更なる情報は 項6.3.1. 「MySQL のテーブルロック方法」 を参照してください。
注意:もしロックされたテーブル上に
ALTER TABLE
を利用すると、ロックが解除される可能性があります。詳しくは
項B.1.7.1. 「Problems with ALTER TABLE
」
を参照してください。