官网地址:MySQL :: MySQL 5.7 Reference Manual :: 13.3.5 LOCK TABLES and UNLOCK TABLES Statements
欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯.
Mysql5.7参考手册 / ... / 锁表和解锁表声明
13.3.5锁表和解锁表
language-sql
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 将视图中使用的所有基表添加到要锁定的表集并自动锁定它们。从我的5.7.32开始, LOCK TABLES 检查视图定义器是否在视图基础表上拥有适当的权限。
如果你明确锁定一张桌子LOCK TABLES ,触发器中使用的任何表也会隐式锁定,如 锁桌和触发器 .
UNLOCK TABLES 显式地释放当前会话所持有的任何表锁。LOCK TABLES 在获取新锁之前,隐式地释放当前会话持有的任何表锁。
另一种用途 UNLOCK TABLES 是释放通过FLUSH TABLES WITH READ LOCK 语句,它使您能够锁定所有数据库中的所有表。看第13.7.6.3节,"齐平陈述" .(这是一个非常方便的备份方法,如果您有一个文件系统,如VERITAS,可以及时进行快照。)
表锁只保护其他会话不适当的读取或写入。举行会议WRITE
锁可以执行表级操作,例如 DROP TABLE 或 TRUNCATE TABLE .举行的届会aREAD
洛克,DROP TABLE 和TRUNCATE TABLE 不允许采取行动。
以下讨论只适用于非TEMPORARY
表格。LOCK TABLES 允许(但被忽略) TEMPORARY
表表可以由创建它的会话自由访问,不管其他锁定可能是有效的。不需要锁,因为没有其他会话可以看到表。
表锁获取
若要在当前会话中获取表锁,请使用 LOCK TABLES 获取元数据锁的语句(参见 8.11.4节,"元数据锁定" ).
以下类型的锁可供选择:
READ [LOCAL]
洛克:
-
持有锁的会话可以读取表(但不能写入表)。
-
多个会议可获得
READ
同时锁好桌子。 -
其他会议可以阅读表格,而不需要显式获取
READ
锁定。 -
...
LOCAL
使不冲突 INSERT 由其他会话执行的语句(并发插入),在锁举行期间执行。(见8.11.3节,"并发插入" .) However,READ LOCAL
如果您要使用服务器外部的进程操作数据库,则无法使用此锁。用于InnoDB
表格,READ LOCAL
就像READ
.
[LOW_PRIORITY] WRITE
洛克:
-
持有锁的会话可以读写表.
-
只有持有锁的会话才能访问表.在释放锁之前,任何其他会话都无法访问它。
-
将表格的请求按其他会话进行锁定,同时
WRITE
上锁了。 -
...
LOW_PRIORITY
修饰不起作用。在以前的mysql版本中,它影响了锁定行为,但这不再是真的。现在它被弃用了,它的使用产生了一个警告。使用WRITE
没有LOW_PRIORITY
相反。
WRITE
一般情况下,锁的优先权高于READ
锁以确保更新被尽快处理。这意味着,如果一个会议获得了READ
锁定然后另一个会话请求WRITE
锁,随后 READ
锁定请求要等到要求WRITE
锁已获得并释放了它.(本政策的一个例外可能是 max_write_lock_count 系统变量;见8.11.4节,"元数据锁定" .)
如果LOCK TABLES 语句必须等待任何一个表上的其他会话所持有的锁,直到获得所有锁。
一个需要锁的会话必须获得它在一个单一的锁中所需要的所有锁LOCK TABLES 声明。当这样获得的锁举行时,会话只能访问锁定的表。例如,在下面的语句顺序中,尝试访问时会出现错误t2
因为它没有被锁在 LOCK TABLES 声明:
language-sql
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 .
在使用相同名称的单个查询中,不能多次引用锁定的表。取而代之的是别名,并为表和每个别名获得一个单独的锁:
language-sql
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 因为上锁桌有两个相同的名称。第二个 INSERT 成功是因为表的引用使用了不同的名称。
如果您的语句以别名的方式引用表,则必须使用相同的别名锁定表。不指定别名就无法锁定表:
language-sql
mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES
相反,如果使用别名锁定表,则必须在使用别名的语句中引用表:
language-sql
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
当应用到分区表时,总是锁定或打开整个表;这些语句不支持分区锁修剪。看 第22.6.4节,"分隔和锁定" .
表锁释放
当会话持有的表锁被释放时,它们都同时被释放。会话可以显式地释放它的锁,或者锁可以在某些条件下隐式地释放。
-
会话可以显式地释放锁 UNLOCK TABLES .
-
如果会议发布了ALOCK TABLES 声明在已经持有锁的情况下获取锁,在授予新锁之前,它的现有锁会被隐式释放。
-
如果一个会话开始一个事务(例如 START TRANSACTION ),一个隐含的 UNLOCK TABLES 执行,这导致释放现有的锁。(有关表锁定与事务之间的互动的其他信息,请参阅 表锁定和事务的相互作用 .)
如果客户端会话的连接通常或异常终止,则服务器隐式地释放会话持有的所有表锁(事务和非事务)。如果客户机重新连接,锁就会更长。此外,如果客户机有一个活动事务,则服务器在断开连接时回滚事务,如果重新连接发生,则新会话从启用自动提交开始。因此,客户可能希望禁用自动重新连接。实际上,如果重新连接发生,则不通知客户机,但会丢失任何表锁定或当前事务。由于禁用了自动重新连接,如果连接下降,下一个语句将出现错误。客户端可以检测错误并采取适当的操作,例如重新获取锁或重做事务。看 自动重新连接控制 .
注意事项
如果你用ALTER TABLE 在上锁的桌子上,它可能会被打开。例如,如果你试图ALTER TABLE 操作,结果可能是错误 .要处理这个,在第二个更改之前再次锁定表。另见 B.3.6.1节,"更改表格的问题" . Table '
tbl_name
' was not locked with LOCK TABLES
表锁定和事务的相互作用
LOCK TABLES 和 UNLOCK TABLES 与使用交易的互动情况如下:
-
LOCK TABLES在试图锁定表之前,没有事务安全地隐式提交任何活动事务。
-
UNLOCK TABLES 隐式提交任何活动事务,但仅限于LOCK TABLES 是用来获取表锁的。例如,在下面的一组声明中, UNLOCK TABLES 释放全局读锁,但不提交事务,因为没有表锁有效:
language-sqlFLUSH TABLES WITH READ LOCK; START TRANSACTION; SELECT ... ; UNLOCK TABLES;
-
开始交易(例如,用 START TRANSACTION )隐式提交任何当前事务并释放现有表锁。
-
FLUSH TABLES WITH READ LOCK 获取全局读锁而不是表锁,因此它不受与表锁相同的行为约束。 LOCK TABLES 和 UNLOCK TABLES 关于表锁定和隐式提交。例如, START TRANSACTION 不释放全局读锁。看第13.7.6.3节,"齐平陈述" .
-
其他隐式导致事务被提交的语句不会释放现有的表锁。此类声明的清单见第13.3.3节,"造成默示犯罪的声明" .
-
正确的使用方式LOCK TABLES 和 UNLOCK TABLES 有事务表,例如
InnoDB
表,是开始交易SET autocommit = 0
(非) START TRANSACTION )然后LOCK TABLES ,以及不打电话 UNLOCK TABLES 直到您显式地提交事务。例如,如果你需要写到表上t1
从餐桌上读到t2
,你可以这样做:language-sqlSET autocommit=0; LOCK TABLES t1 WRITE, t2 READ, ...; ... do something with tables t1 and t2 here ... COMMIT; UNLOCK TABLES;
当你打电话的时候LOCK TABLES ,
InnoDB
内部使用自己的表锁,mysql使用自己的表锁。InnoDB
下一次提交时释放其内部表锁,但要释放其表锁,必须调用。 UNLOCK TABLES .你不应该 autocommit = 1 ,因为那时InnoDB
在呼叫后立即释放其内部表锁。LOCK TABLES ,而且死锁很容易发生。InnoDB
不需要获得内部表锁autocommit = 1 ,帮助旧的应用程序避免不必要的死锁。 -
ROLLBACK 不释放表锁。
锁桌和触发器
如果你明确锁定一张桌子LOCK TABLES ,触发器中使用的任何表也会隐式锁定:
-
这些锁的使用时间与那些显式的LOCK TABLES 声明。
-
触发器中使用的表上的锁取决于表是否仅用于读取。如果是这样,读锁就足够了。否则,将使用写入锁。
-
如果一个表被明确锁定用于阅读 LOCK TABLES ,但需要为编写锁定,因为它可能在触发器中被修改,而不是被读取锁定。(也就是说,由于表在触发器中的外观而需要隐式写锁,这将导致表的显式读锁请求转换为写锁请求。)
假设你锁了两张桌子,t1
和 t2
,使用本声明:
language-sql
LOCK TABLES t1 WRITE, t2 READ;
如果t1
或t2
有任何触发器,在触发器中使用的表也被锁定。假设t1
有这样定义的触发器:
language-sql
CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW
BEGIN
UPDATE t4 SET count = count+1
WHERE id = NEW.id AND EXISTS (SELECT a FROM t3);
INSERT INTO t2 VALUES(1, 2);
END;
结果是LOCK TABLES 声明是t1
和 t2
因为它们出现在声明中而被锁定t3
和t4
因为它们在触发器中被使用:
-
t1
已锁定用于写作WRITE
锁定请求。 -
t2
是锁定的,即使请求是READ
锁定。出现这种情况是因为t2
是插入到触发器中的,所以READ
请求被转换成WRITE
请求。 -
t3
因为它只能从触发器内部读取。 -
t4
因为它可能在触发器中更新。
限制和条件
你可以安全使用KILL 终止正在等待表锁的会话。看 第13.7.6.4节,"死亡陈述" .
LOCK TABLES 和 UNLOCK TABLES 不能在存储的程序中使用。
表格performance_schema
数据库无法锁定LOCK TABLES ,除了 表格。 setup_
xxx
锁定的范围LOCK TABLES
是一个单一的mysql服务器。它与ndb集群不兼容,该集群无法在多个实例中强制执行sql级锁。MysqDD .相反,您可以强制锁定API应用程序。看 第21.2.7.10节,"与多个网络数据库集群节点有关的限制" ,详情请参阅。
禁止下列声明: LOCK TABLES 声明生效:CREATE TABLE , CREATE TABLE ... LIKE ,CREATE VIEW , DROP VIEW ,以及存储函数、过程和事件的DDL语句。
对于某些操作,系统表在 mysql
必须访问数据库。例如,HELP 语句要求服务器端帮助表的内容,以及 CONVERT_TZ() 可能需要看一下时差表。服务器根据需要隐式地锁定系统表,以便不需要显式地锁定它们。这些表格按上述方式处理:
language-none
mysql.help_category
mysql.help_keyword
mysql.help_relation
mysql.help_topic
mysql.proc
mysql.time_zone
mysql.time_zone_leap_second
mysql.time_zone_name
mysql.time_zone_transition
mysql.time_zone_transition_type
如果你想明确地WRITE
把这些桌子都锁起来LOCK TABLES 语句,表必须是唯一锁定的;没有其他的表可以用相同的语句锁定。
一般来说,你不需要锁桌子,因为所有的桌子 UPDATE 语句是原子的;任何其他会话都不能干扰当前正在执行的任何其他SQL语句。然而,在一些情况下,锁定表可能提供了好处:
-
如果你要在一组
MyISAM
表,锁定你将要使用的桌子要快得多。锁定的MyISAM
表加速了插入、更新或删除的速度,因为mysql在锁定表之前不会冲洗密钥缓存 UNLOCK TABLES 是叫。通常,键缓存在每个SQL语句之后进行刷新。锁定表的缺点是没有一个会话可以更新
READ
-上锁桌(包括持有锁的桌),任何会议都无法进入AWRITE
-上锁的桌子不是拿锁的那张。 -
如果您正在使用非事务性存储引擎的表,则必须使用LOCK TABLES 如果您想确保没有其他会话修改表 SELECT 以及 UPDATE .这里的例子要求LOCK TABLES 安全执行:
language-sqlLOCK 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 ,另一个会话可能会在
trans
执行之间的表格 SELECT 和 UPDATE 声明。
你可以避免使用LOCK TABLES 在许多情况下,使用相对更新( )或 职能。 UPDATE customer SET
value
=
value
+
new_value
LAST_INSERT_ID()
在某些情况下,还可以通过使用用户级咨询锁功能来避免锁定表 GET_LOCK() 和 RELEASE_LOCK() .这些锁保存在服务器的散列表中,并通过 pthread_mutex_lock()
和 pthread_mutex_unlock()
为了高速。看 第12.14节,"锁定功能" .
看8.11.1节,"内部锁定方法" ,以获取有关锁定策略的更多资料。