MySQL事务和锁04

  官网地址:MySQL :: MySQL 5.7 Reference Manual :: 13.3.5 LOCK TABLES and UNLOCK TABLES Statements

欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯.

Mysql5.7参考手册  /  ...  /  锁表和解锁表声明

13.3.5锁表和解锁表

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 声明:

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 .

在使用相同名称的单个查询中,不能多次引用锁定的表。取而代之的是别名,并为表和每个别名获得一个单独的锁:

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 成功是因为表的引用使用了不同的名称。

如果您的语句以别名的方式引用表,则必须使用相同的别名锁定表。不指定别名就无法锁定表:

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 当应用到分区表时,总是锁定或打开整个表;这些语句不支持分区锁修剪。看 第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 释放全局读锁,但不提交事务,因为没有表锁有效:

    FLUSH 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 ,你可以这样做:

    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 ,但需要为编写锁定,因为它可能在触发器中被修改,而不是被读取锁定。(也就是说,由于表在触发器中的外观而需要隐式写锁,这将导致表的显式读锁请求转换为写锁请求。)

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

LOCK TABLES t1 WRITE, t2 READ;

如果t1 或t2 有任何触发器,在触发器中使用的表也被锁定。假设t1 有这样定义的触发器:

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() 可能需要看一下时差表。服务器根据需要隐式地锁定系统表,以便不需要显式地锁定它们。这些表格按上述方式处理:

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 安全执行:

    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 执行之间的表格 SELECT 和 UPDATE 声明。

你可以避免使用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节,"内部锁定方法" ,以获取有关锁定策略的更多资料。

你可能感兴趣的:(mysql,数据库)