Documentation Home
MySQL 5.6 リファレンスマニュアル
Download this Manual
EPUB - 7.5Mb
HTML Download (TGZ) - 7.2Mb
HTML Download (Zip) - 7.2Mb


13.3.5 LOCK TABLES および UNLOCK TABLES 構文

LOCK TABLES
    tbl_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 は、そのビューで使用されているすべてのベーステーブルをロックされるテーブルのセットに追加し、それらのテーブルを自動的にロックします。セクション13.3.5.2「LOCK TABLES とトリガー」で説明されているように、LOCK TABLES によって明示的にテーブルをロックした場合は、トリガーで使用されているテーブルもすべて暗黙的にロックされます。

UNLOCK TABLES は、現在のセッションによって保持されているテーブルロックをすべて明示的に解放します。LOCK TABLES は、新しいロックを取得する前に、現在のセッションによって保持されているテーブルロックをすべて暗黙的に解放します。

UNLOCK TABLES の別の使用法として、すべてのデータベース内のすべてのテーブルをロックできる FLUSH TABLES WITH READ LOCK ステートメントによって取得されたグローバルな読み取りロックの解放があります。セクション13.7.6.3「FLUSH 構文」を参照してください。(これは、特定時点のスナップショットを取得できる、Veritas などのファイルシステムがある場合にバックアップを取得するための非常に便利な方法です。)

テーブルロックでは、ほかのセッションによる不適切な読み取りまたは書き込みからのみ保護されます。WRITE ロックを保持しているセッションは、DROP TABLETRUNCATE TABLE などのテーブルレベルの操作を実行できます。READ ロックを保持しているセッションの場合、DROP TABLE および TRUNCATE TABLE 操作は許可されません。TRUNCATE TABLE 操作はトランザクションセーフではないため、セッションがアクティブなトランザクション中または READ ロックを保持している間にこの操作を行おうとすると、エラーが発生します。

次の説明は、TEMPORARY 以外のテーブルにのみ適用されます。LOCK TABLESTEMPORARY テーブルに対して許可されます (ただし、無視されます)。テーブルは、ほかのどのようなロックが有効になっているかには関係なく、そのテーブルが作成されたセッションから自由にアクセスできます。ほかのどのセッションもそのテーブルを参照できないため、ロックは必要ありません。

LOCK TABLES の使用に関するその他の条件や、LOCK TABLES が有効になっている間は使用できないステートメントについては、セクション13.3.5.3「テーブルロックの制限と条件」を参照してください。

ロック取得のルール

現在のセッション内でテーブルロックを取得するには、LOCK TABLES ステートメントを使用します。次のロックタイプを使用できます。

READ [LOCAL] ロック:

  • このロックを保持しているセッションは、テーブルを読み取ることができます (ただし、書き込みはできません)。

  • 複数のセッションが同時にテーブルに対する READ ロックを取得できます。

  • ほかのセッションは、READ ロックを明示的に取得することなく、テーブルを読み取ることができます。

  • LOCAL 修飾子を使用すると、ロックが保持されている間、ほかのセッションによる競合しない INSERT ステートメント (並列挿入) を実行できます。(セクション8.10.3「同時挿入」を参照してください。)ただし、ロックを保持している間、サーバーの外部にあるプロセスを使用してデータベースを操作しようとしている場合は、READ LOCAL を使用できません。InnoDB テーブルの場合、READ LOCALREAD と同じです。

[LOW_PRIORITY] WRITE ロック:

  • このロックを保持しているセッションは、テーブルの読み取りおよび書き込みが可能です。

  • このロックを保持しているセッションだけがテーブルにアクセスできます。ロックが解放されるまで、ほかのどのセッションもアクセスできません。

  • WRITE ロックが保持されている間、テーブルに対するほかのセッションからのロック要求はブロックされます。

  • LOW_PRIORITY 修飾子は何の効果もありません。以前のバージョンの MySQL では、ロックの動作に影響を与えましたが、これは当てはまらなくなっています。MySQL 5.6.5 の時点では、これは非推奨であり、使用すると警告が生成されます。代わりに、LOW_PRIORITY のない WRITE を使用してください。

LOCK TABLES ステートメントが、いずれかのテーブルに対するほかのセッションによって保持されているロックのために待機する必要がある場合、このステートメントはすべてのロックを取得できるまでブロックされます。

ロックが必要なセッションは、必要なすべてのロックを 1 つの LOCK TABLES ステートメントで取得する必要があります。このように取得されたロックが保持されている間、このセッションは、ロックされたテーブルにのみアクセスできます。たとえば、次のステートメントシーケンスでは、t2LOCK 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;

WRITE ロックは通常、更新ができるだけ早く処理されるように、READ ロックより高い優先度を持っています。つまり、あるセッションが READ ロックを取得したあと、別のセッションが WRITE ロックを要求した場合は、WRITE ロックを要求したセッションがロックを取得して解放するまで、以降の READ ロック要求が待たされます。

LOCK TABLES は、次のようにロックを取得します。

  1. ロックされるすべてのテーブルを内部で定義された順序でソートします。ユーザーから見て、この順序は定義されていません。

  2. テーブルを読み取りおよび書き込みロックでロックする場合は、書き込みロック要求を読み取りロック要求の前に配置します。

  3. セッションがすべてのロックを取得するまで、1 回につき 1 つのテーブルをロックします。

このポリシーによって、テーブルロックでデッドロックが発生しないことが保証されます。

注記

LOCK TABLES または UNLOCK TABLES は、パーティション化されたテーブルに適用された場合、常にテーブル全体をロックまたはロック解除します。これらのステートメントは、パーティションロックプルーニングをサポートしていません。セクション19.6.4「パーティショニングとロック」を参照してください。

ロック解放のルール

セッションによって保持されているテーブルロックが解放される場合は、すべてのテーブルロックが一度に解放されます。セッションは明示的にロックを解放できます。また、特定の状況で、ロックが暗黙的に解放される場合もあります。

  • セッションは、UNLOCK TABLES によって明示的にロックを解放できます。

  • セッションがすでにロックを保持している間にロックを取得するために LOCK TABLES ステートメントを発行した場合は、新しいロックが付与される前に、その既存のロックが暗黙的に解放されます。

  • セッションが (たとえば、START TRANSACTION で) トランザクションを開始した場合は、暗黙的な UNLOCK TABLES が実行され、既存のロックが解放されます。(テーブルロックとトランザクションの間の通信の詳細は、セクション13.3.5.1「テーブルロックとトランザクションの通信」を参照してください。)

クライアントセッションの接続が (正常または異常にかかわらず) 終了した場合、サーバーは、そのセッションによって保持されているすべてのテーブルロック (トランザクションおよび非トランザクション) を暗黙的に解放します。そのクライアントが再接続した場合、ロックは有効でなくなります。さらに、クライアントにアクティブなトランザクションがある場合、サーバーは切断時にそのトランザクションをロールバックし、再接続が発生した場合は、自動コミットが有効になった状態で新しいセッションが開始されます。このため、クライアントは自動再接続を無効にすることが必要になる場合があります。自動再接続が有効な場合、再接続が発生してもクライアントには通知されませんが、すべてのテーブルロックまたは現在のトランザクションが失われます。自動再接続が無効になっている場合は、接続が削除されると、発行された次のステートメントに対してエラーが発生します。クライアントはそのエラーを検出し、ロックの再取得やトランザクションの再実行などの適切なアクションを実行できます。セクション23.8.16「自動再接続動作の制御」を参照してください。

注記

ロックされたテーブル上で ALTER TABLE を使用すると、そのテーブルがロック解除される場合があります。たとえば、2 番目の ALTER TABLE 操作を試みると、エラー「テーブル 'tbl_name' は LOCK TABLES でロックされていません」が発生する場合があります。これに対処するには、2 番目の変更の前にテーブルを再度ロックします。セクションB.5.7.1「ALTER TABLE での問題」も参照してください。


User Comments
  Posted by Max Matson on May 21, 2007
Note that while you are allowed to drop a table that you have a lock on, you can not subsequently create the table. Attempts to create the table without first issueing unlock tables results in a "table not locked" error. Therefore, you can't use lock tables to process data through several staging tables where you would drop and create the intermidiate tables. Truncate also won't work, as stated in the manual. The only option that will work is to delete from the table, but this is a slow operation.

  Posted by Rick James on February 23, 2009
FLUSH TABLES WITH READ LOCK does _not_ seem to put InnoDB into a sufficiently quiesced state for Linux LVM snapshot.
  Posted by Daniel Kadosh on October 26, 2009
@Rick James -- a solution I use to lock InnoDB tables before snapshots that I use is below. CAVEAT: I haven't done any real test for "is mysql fully quiesced".

1) I use an XFS filesystem, which you can freeze right before taking the LVM snapshot. I mount this filesystem on /var/lib/mysql (RedHat/CentOS default location).

2) I have a mysql script that does the whole thing like this, and it's based on an Amazon EC2 tutorial I read
http://developer.amazonwebservices.com/connect/entry!default.jspa?categoryID=112&externalID=1663

FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;
SYSTEM xfs_freeze -f /var/lib/mysql;
SYSTEM YOUR_SCRIPT_TO_CREATE_SNAPSHOT.sh;
SYSTEM xfs_freeze -u /var/lib/mysql;
UNLOCK TABLES;
EXIT;

  Posted by Andrew Atkinson on February 25, 2010
For a filesystem snapshot of innodb, we find that setting innodb_max_dirty_pages_pct to zero; doing a 'flush tables with readlock'; and then waiting for the innodb state to reach 'Main thread process no. \d+, id \d+, state: waiting for server activity' is sufficient to quiesce innodb.

You will also need to issue a slave stop if you're backing up a slave whose relay logs are being written to its data directory.

Don't forget to set innodb_max_dirty_pages_pct back to it's normal value and resume slaving afterwards. :-)

Hope this helps.
  Posted by Ilguiz Latypov on August 5, 2010
The chapter does not explain what MySQL sessions are. I could not find an explanation at all. If session is client-server activity limited by connection, this could be explicitly stated somewhere in the glossary and linked to from this chapter of the manual.

  Posted by Frederic Marand on November 30, 2010
Note that, while a WRITE lock will lock new SELECT queries until it is converted to a READ lock or released via UNLOCK, it will not prevent SELECT queries already in the query cache from returning the cached results.

This marginal effect will be limited, though: in most cases the session LOCKing a table will be writing to the same table before UNLOCKing, which will cause the query cache to be flushed for that table.
  Posted by Larry Clapp on September 13, 2011
If you need to do things with tables not normally supported by read or write locks (like dropping or truncating a table), and you're able to cooperate, you can try this: Use a semaphore table, and create two sessions per process. In the first session, get a read or write lock on the semaphore table, as appropriate. In the second session, do all the stuff you need to do with all the other tables.

This is just using the database to create and manage a semaphore instead of using the OS directly (and of course it's not "real" locking but only advisory locking, so it won't work if you can't cooperate with other users), but on the other hand using the database allows the semaphore to be accessed by multiple other servers accessing the DB over a network.
Sign Up Login You must be logged in to post a comment.