LOCK TABLES and 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
,则触发器中使用的任何表也会隐式锁定.
UNLOCK TABLES
显式释放当前会话持有的所有表锁。 在获取新锁之前,隐式释放当前会话持有的所有表锁。
UNLOCK TABLES
的另一种用法是释放通过该FLUSH TABLES WITH READ LOCK
语句获取的全局读取锁定,这使您可以锁定所有数据库中的所有表。
表锁只能防止其他会话进行不适当的读取或写入。持有WRITE
锁的会话可以执行表级操作,例如 DROP TABLE
或 TRUNCATE TABLE
。对于持有会话READ
锁,DROP TABLE和
TRUNCATE TABLE
操作是不允许的。
以下讨论仅适用于非TEMPORARY
表。LOCK TABLES
允许(但忽略) TEMPORARY
表。
在当前会话中获取表锁,使用 LOCK TABLES
语句
READ [LOCAL]
锁:
持有锁的会话可以读取表(但不能写入表)。
多个会话可以同时获取该表的READ锁。
其他会话可以在不显式获取READ
锁的情况下读取表。
使用LOCAL可以在并发插入时不产生冲突。
但是,如果您要在持有READ LOCAL锁的同时使用服务器外部的进程来操作数据库, 则不能使用它。对于 InnoDB
表,READ LOCAL
与READ相同。
[LOW_PRIORITY] WRITE
锁:
持有锁的会话可以读写表。
只有持有锁的会话才能访问该表。在释放锁之前,没有其他会话可以访问它。
保持WRITE锁定状态时,其他会话对表的锁定请求将阻塞。
该LOW_PRIORITY
修饰符无效。在以前的MySQL版本中,它影响了锁定行为,但现在不再如此。现在已弃用,使用它会产生警告。使用WRITE
不带 LOW_PRIORITY
。
需要锁的会话必须在单个锁表语句中获取所需的所有锁。当这样获得的锁被持有时,会话只能访问锁定的表。例如,在以下语句序列中,尝试访问t2时出错,因为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
不能在同一个查询中使用相同的名称多次引用锁定的表。请改用别名,并为表和每个别名获取单独的锁:
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;
如果您的语句通过别名引用表,则必须使用相同的别名锁定表。如果不指定别名,则无法锁定表:
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;
表锁定和事务的交互
LOCK TABLES和
UNLOCK TABLES
与事务进行交互,如下所示:
LOCK TABLES
不是事务安全的,而是在尝试锁定表之前隐式提交任何活动事务。
UNLOCK TABLES
隐式提交任何活动事务,但前提是LOCK TABLES
已用于获取表锁。例如,在以下语句集中, UNLOCK TABLES
释放全局读取锁,但由于没有有效表锁,因此不提交事务:
FLUSH TABLES WITH READ LOCK;
START TRANSACTION;
SELECT ... ;
UNLOCK TABLES;
开始事务(例如,使用START TRANSACTION),会隐式提交任何当前事务,并释放存在的表锁。
FLUSH TABLES WITH READ LOCK
获得全局读锁定,而不是表锁,所以不会受到像 LOCK TABLES
and UNLOCK TABLES关于表锁定和隐式提交一样的约束,例如,
START TRANSACTION不会释放全局读锁。
其他隐式导致事务提交的语句不会释放现有的表锁。
在事务表中正确的使用lock tables 和 unlock tables ,比如innodb 表,一个事务开始用SET autocommit=0(而不是start transaction) 后面跟着 lock tables,最后直到显示的提交commit后,才可以使用unlock tables.比如,你需要写表t1和读表t2,可以如下:
SET autocommit=0; LOCK TABLES t1 WRITE, t2 READ, ...; ... do something with tables t1 and t2 here ... COMMIT; UNLOCK TABLES;
当你用lock tables时,innodb 使用它自己内部的表锁,MYSQL使用它自己的表锁。在提交时innodb释放它内部的表锁,但是对于MYSQL,必须使用UNLOCK TABLES才会释放它的锁。不能设置autocommit=1,因为这样在lock tables 后,innodb会立即释放它的内部表锁,容易发生死锁。如果autocommit=1,innodb不会一直要求内部表锁,是为了帮助老的应用避免非必要的死锁。
ROLLBACK不会释放表锁。