MySQL事务和锁04

官网地址: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 TABLETRUNCATE TABLE .举行的届会aREAD 洛克,DROP TABLETRUNCATE 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 TABLESUNLOCK TABLES 当应用到分区表时,总是锁定或打开整个表;这些语句不支持分区锁修剪。看 第22.6.4节,"分隔和锁定" .

表锁释放

当会话持有的表锁被释放时,它们都同时被释放。会话可以显式地释放它的锁,或者锁可以在某些条件下隐式地释放。

如果客户端会话的连接通常或异常终止,则服务器隐式地释放会话持有的所有表锁(事务和非事务)。如果客户机重新连接,锁就会更长。此外,如果客户机有一个活动事务,则服务器在断开连接时回滚事务,如果重新连接发生,则新会话从启用自动提交开始。因此,客户可能希望禁用自动重新连接。实际上,如果重新连接发生,则不通知客户机,但会丢失任何表锁定或当前事务。由于禁用了自动重新连接,如果连接下降,下一个语句将出现错误。客户端可以检测错误并采取适当的操作,例如重新获取锁或重做事务。看 自动重新连接控制 .
注意事项

如果你用ALTER TABLE 在上锁的桌子上,它可能会被打开。例如,如果你试图ALTER TABLE 操作,结果可能是错误 .要处理这个,在第二个更改之前再次锁定表。另见 B.3.6.1节,"更改表格的问题" . Table 'tbl_name' was not locked with LOCK TABLES

表锁定和事务的相互作用

LOCK TABLESUNLOCK TABLES 与使用交易的互动情况如下:

  • LOCK TABLES在试图锁定表之前,没有事务安全地隐式提交任何活动事务。

  • UNLOCK TABLES 隐式提交任何活动事务,但仅限于LOCK TABLES 是用来获取表锁的。例如,在下面的一组声明中, UNLOCK TABLES 释放全局读锁,但不提交事务,因为没有表锁有效:

    language-sql 复制代码
    FLUSH TABLES WITH READ LOCK;
    START TRANSACTION;
    SELECT ... ;
    UNLOCK TABLES;
  • 开始交易(例如,用 START TRANSACTION )隐式提交任何当前事务并释放现有表锁。

  • FLUSH TABLES WITH READ LOCK 获取全局读锁而不是表锁,因此它不受与表锁相同的行为约束。 LOCK TABLESUNLOCK TABLES 关于表锁定和隐式提交。例如, START TRANSACTION 不释放全局读锁。看第13.7.6.3节,"齐平陈述" .

  • 其他隐式导致事务被提交的语句不会释放现有的表锁。此类声明的清单见第13.3.3节,"造成默示犯罪的声明" .

  • 正确的使用方式LOCK TABLESUNLOCK TABLES 有事务表,例如 InnoDB 表,是开始交易SET autocommit = 0 (非) START TRANSACTION )然后LOCK TABLES ,以及不打电话 UNLOCK TABLES 直到您显式地提交事务。例如,如果你需要写到表上 t1 从餐桌上读到 t2 ,你可以这样做:

    language-sql 复制代码
    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 下一次提交时释放其内部表锁,但要释放其表锁,必须调用。 UNLOCK TABLES .你不应该 autocommit = 1 ,因为那时InnoDB 在呼叫后立即释放其内部表锁。LOCK TABLES ,而且死锁很容易发生。 InnoDB 不需要获得内部表锁autocommit = 1 ,帮助旧的应用程序避免不必要的死锁。

  • ROLLBACK 不释放表锁。

锁桌和触发器

如果你明确锁定一张桌子LOCK TABLES ,触发器中使用的任何表也会隐式锁定:

  • 这些锁的使用时间与那些显式的LOCK TABLES 声明。

  • 触发器中使用的表上的锁取决于表是否仅用于读取。如果是这样,读锁就足够了。否则,将使用写入锁。

  • 如果一个表被明确锁定用于阅读 LOCK TABLES ,但需要为编写锁定,因为它可能在触发器中被修改,而不是被读取锁定。(也就是说,由于表在触发器中的外观而需要隐式写锁,这将导致表的显式读锁请求转换为写锁请求。)

假设你锁了两张桌子,t1t2 ,使用本声明:

language-sql 复制代码
LOCK TABLES t1 WRITE, t2 READ;

如果t1t2 有任何触发器,在触发器中使用的表也被锁定。假设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 声明是t1t2 因为它们出现在声明中而被锁定t3t4 因为它们在触发器中被使用:

  • t1 已锁定用于写作 WRITE 锁定请求。

  • t2 是锁定的,即使请求是READ 锁定。出现这种情况是因为t2 是插入到触发器中的,所以READ 请求被转换成WRITE 请求。

  • t3因为它只能从触发器内部读取。

  • t4因为它可能在触发器中更新。

限制和条件

你可以安全使用KILL 终止正在等待表锁的会话。看 第13.7.6.4节,"死亡陈述" .

LOCK TABLESUNLOCK 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 -上锁桌(包括持有锁的桌),任何会议都无法进入A WRITE -上锁的桌子不是拿锁的那张。

  • 如果您正在使用非事务性存储引擎的表,则必须使用LOCK TABLES 如果您想确保没有其他会话修改表 SELECT 以及 UPDATE .这里的例子要求LOCK TABLES 安全执行:

    language-sql 复制代码
    LOCK 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 执行之间的表格 SELECTUPDATE 声明。

你可以避免使用LOCK TABLES 在许多情况下,使用相对更新( )或 职能。 UPDATE customer SET value =value +new_valueLAST_INSERT_ID()

在某些情况下,还可以通过使用用户级咨询锁功能来避免锁定表 GET_LOCK()RELEASE_LOCK() .这些锁保存在服务器的散列表中,并通过 pthread_mutex_lock()pthread_mutex_unlock() 为了高速。看 第12.14节,"锁定功能" .

8.11.1节,"内部锁定方法" ,以获取有关锁定策略的更多资料。

相关推荐
Java探秘者3 小时前
Maven下载、安装与环境配置详解:从零开始搭建高效Java开发环境
java·开发语言·数据库·spring boot·spring cloud·maven·idea
2301_786964363 小时前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
苹果醋33 小时前
大模型实战--FastChat一行代码实现部署和各个组件详解
java·运维·spring boot·mysql·nginx
阿维的博客日记4 小时前
图文并茂解释水平分表,垂直分表,水平分库,垂直分库
数据库·分库分表
wrx繁星点点5 小时前
事务的四大特性(ACID)
java·开发语言·数据库
小小娥子6 小时前
Redis的基础认识与在ubuntu上的安装教程
java·数据库·redis·缓存
DieSnowK6 小时前
[Redis][集群][下]详细讲解
数据库·redis·分布式·缓存·集群·高可用·新手向
计算机学姐6 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
-XWB-6 小时前
【MySQL】数据目录迁移
数据库·mysql
老华带你飞6 小时前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计