LOCK TABLEStbl_name
[[AS]alias
]lock_type
[,tbl_name
[[AS]alias
]lock_type
] ...lock_type
: READ [LOCAL] | [LOW_PRIORITY] WRITE UNLOCK TABLES
MySQL では、ほかのセッションと連携してテーブルにアクセスする目的で、またはあるセッションにテーブルへの排他的アクセスが必要な期間中にほかのセッションがテーブルを変更できないようにするために、クライアントセッションはテーブルロックを明示的に取得できます。セッションは、それ自体のためにのみロックを取得したり解放したりできます。あるセッションが、別のセッションのためにロックを取得したり、別のセッションによって保持されているロックを解放したりすることはできません。
ロックは、トランザクションをエミュレートするために、またはテーブル更新時の速度を向上させるために使用できます。これについては、この節のあとの方でさらに詳細に説明します。
LOCK TABLES
は、現在のクライアントセッションのテーブルロックを明示的に取得します。テーブルロックは、ベーステーブルまたはビューに対して取得できます。各オブジェクトをロックするには、LOCK
TABLES
権限および
SELECT
権限が必要です。
ビューのロックの場合、LOCK
TABLES
は、そのビューで使用されているすべてのベーステーブルをロックされるテーブルのセットに追加し、それらのテーブルを自動的にロックします。項8.4.5.2. 「LOCK TABLES
とトリガー」
で説明されているように、LOCK
TABLES
によってテーブルを明示的にロックする場合は、トリガーで使用されているテーブルもすべて暗黙的にロックされます。
UNLOCK
TABLES
は、現在のセッションによって保持されているテーブルロックをすべて明示的に解放します。
UNLOCK
TABLES
の別の使用法として、すべてのデータベース内のすべてのテーブルをロックできる
FLUSH
TABLES WITH READ LOCK
ステートメントによって取得されたグローバルな読み取りロックの解放があります。詳しくは項8.5.6.3. 「FLUSH
構文」を参照してください。(これは、特定時点のスナップショットを取得できる、Veritas
などのファイルシステムがある場合にバックアップを取得するための非常に便利な方法です。)
次の説明は、TEMPORARY
以外のテーブルにのみ適用されます。LOCK
TABLES
は、TEMPORARY
テーブルに対して許可されます
(ただし、無視される)。テーブルは、ほかのどのようなロックが有効になっているかには関係なく、そのテーブルが作成されたセッションから自由にアクセスできます。ほかのセッションはそのテーブルを参照できないため、ロックは必要ありません。
次の一般的な規則は、特定のセッションによるロックの取得と解放に適用されます。
テーブルロックは、LOCK
TABLES
によって取得されます。
LOCK TABLES
ステートメントが、任意のテーブル上のほかのセッションによって保持されているロックのために待機する必要がある場合は、すべてのロックを取得できるまでブロックされます。
テーブルロックは、UNLOCK
TABLES
によって明示的に解放されます。
テーブルロックは、次の条件の下に暗黙的に解放されます。
LOCK
TABLES
は、新しいロックを取得する前に、そのセッションによって現在保持されているテーブルロックをすべて解放します。
トランザクションを
(たとえば、START
TRANSACTION
によって)
開始すると、UNLOCK
TABLES
が暗黙的に実行されます。(テーブルロックとトランザクションの間の対話の詳細については、項8.4.5.1. 「テーブルロックとトランザクションの対話」
を参照してください。)
クライアント接続が削除された場合、サーバーは、そのクライアントによって保持されているテーブルロックを解放します。クライアントが再接続された場合、ロックは有効でなくなります。 さらに、クライアントにアクティブなトランザクションがある場合、サーバーは切断時にそのトランザクションをロールバックし、再接続が発生した場合は、自動コミットが有効になった状態で新しいセッションが開始されます。このため、クライアントは自動再接続を無効にすることが必要になる場合があります。自動再接続が有効な場合、再接続が発生してもクライアントには通知されませんが、すべてのテーブルロックまたは現在のトランザクションが失われます。自動再接続が無効になっている場合は、接続が削除されると、発行された次のステートメントに対してエラーが発生します。クライアントはそのエラーを検出し、ロックの再取得やトランザクションの再実行などの適切なアクションを実行できます。Controlling Automatic Reconnection Behavior を参照してください。
ロックされたテーブル上で
ALTER TABLE
を使用すると、そのテーブルがロック解除される場合があります。Problems with ALTER TABLE
を参照してください。
テーブルロックは、別のクライアントによる不適切な読み込みや書き込みに対してのみ保護します。ロックを保持しているクライアントは、それが読み取りロックだとしても、DROP
TABLE
のようなテーブルレベル操作を行うことができます。切り捨て操作はトランザクションセーフではないので、もし、アクティブなトランザクションの実行中や、テーブルロックを保持している最中にクライアントがそれを行おうとすると、エラーが発生します。
ロックが必要なセッションは、必要なすべてのロックを
1 つの LOCK
TABLES
ステートメントで取得する必要があります。このように取得されたロックが保持されている間、このセッションは、ロックされたテーブルにのみアクセスできます。たとえば、次のステートメントシーケンスでは、t2
が LOCK TABLES
ステートメントでロックされていないため、このテーブルにアクセスしようとするとエラーが発生します。
mysql>LOCK TABLES t1 READ;
mysql>SELECT COUNT(*) FROM t1;
+----------+ | COUNT(*) | +----------+ | 3 | +----------+ mysql>SELECT COUNT(*) FROM t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES
INFORMATION_SCHEMA
データベース内のテーブルは例外です。これらのテーブルは、セッションが
LOCK TABLES
によって取得されたテーブルロックを保持している間であっても、明示的にロックすることなくアクセスできます。
ロックされたテーブルを、同じ名前を使用して 1 つのクエリーで複数回参照することはできません。代わりにエイリアスを使用し、そのテーブルと各エイリアスのための個別のロックを取得します。
mysql>LOCK TABLE t WRITE, t AS t1 READ;
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;
最初の INSERT
では、ロックされたテーブルに対する同じ名前への参照が
2 つ存在するため、エラーが発生します。2
番目の INSERT
は、テーブルへの参照で異なる名前が使用されるため、成功します。
もしステートメントがエイリアスを利用してテーブルを参照するなら、同じエイリアスを利用してテーブルをロックする必要があります。エイリアスを指定しないでテーブルをロックすることはできません。
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
と
READ LOCAL
の違いは、READ LOCAL
ではロックが保持されている間、競合しない
INSERT
ステートメント (並列挿入)
を実行できることです。ただし、ロックを保持している間、サーバーの外部にあるプロセスを使用してデータベースを操作する場合は、READ
LOCAL
を使用できません。InnoDB
テーブルに対しては、READ
LOCAL
は READ
と同じです。
WRITE
ロックは通常、更新がなるべく速く行われるよう、READ
ロックよりも高い優先順位を持ちます。つまり、あるセッションが
READ
ロックを取得したあと、別のセッションが
WRITE
ロックを要求した場合は、WRITE
ロックを要求したセッションがロックを取得して解放するまで、以降の
READ
ロック要求が待たされます。それに対して、LOW_PRIORITY
WRITE
ロックに対する要求の場合は、LOW_PRIORITY
WRITE
要求が待機している間にほかのセッションによる以降の
READ
ロック要求が発生した場合は、それらの要求を最初に満足できます。LOW_PRIORITY
WRITE
ロックは、最終的にどのセッションも
READ
ロックを保持していない時間が確実に存在する場合にのみ使用してください。トランザクションモード
(autocommit = 0) にある
InnoDB
テーブルの場合、待機中の
LOW_PRIORITY WRITE
ロックは通常の WRITE
ロックと同様の機能を持ち、以降の
READ
ロック要求を待機させます。
LOCK TABLES
は、次のようにロックを取得します。
ロックされるすべてのテーブルを内部定義順に並べ替えます。ユーザーの立場からは、この順番は定義されていません。
読み取りロックと書き込みロックによってテーブルをロックする場合は、書き込みロック要求を読み取りロック要求の前に置きます。
セッションがすべてのロックを取得するまで、一度に 1 つのテーブルをロックします。
.この方法は、テーブルロックにデッドロックが起きないことを保証します。ただし、このポリシーに関して、ほかの点も認識しておく必要があります。テーブルに対して
LOW_PRIORITY WRITE
ロックを使用している場合は、READ
ロックを必要とするほかのセッションがなくなるまで、MySQL
がこの特定のロックを待機することのみを示します。セッションが
WRITE
ロックを取得し、ロックテーブルリスト内の次のテーブルのためのロックの取得を待機している場合、ほかのセッションはすべて
WRITE
ロックが解放されるのを待機します。もしこれが、ご利用のアプリケーションにとって深刻な問題となってしまったら、いくつかのテーブルをトランザクションセーフテーブルに変換することを考慮するべきです。