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 TABLETRUNCATE 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不会释放表锁。

原文地址:https://www.cnblogs.com/wonchaofan/p/13521240.html