MySQL使用元数据锁定来管理对数据库对象的并发访问,并确保数据的一致性。元数据锁定不仅适用于表,还适用于模式、存储程序(过程、函数、触发器、计划事件)、表空间、使用get_lock()
功能(参见第12.15节,“锁定函数”)和用锁定服务获取的锁定第5.6.9.1节“锁定服务”.
性能模式metadata_locks
表公开了元数据锁信息,这些信息对于查看哪些会话持有锁、正在阻塞等待锁等等非常有用。有关详细信息,请参见第27.12.13.3节,“metadata_locks表”.
元数据锁定确实涉及一些开销,随着查询量的增加而增加。元数据争用增加了多个查询尝试访问相同对象的越多。
元数据锁定不是表定义缓存的替代,其互斥锁和锁定不同lock_open.
互斥。以下讨论提供了有关元数据锁定工作原理的一些信息。
如果给定的锁有多个等待者,则优先级最高的锁请求将首先得到满足,并出现与max_write_lock_count
系统变量。写入锁定请求具有比读锁定请求更高的优先级。但是,如果max_write_lock_count
如果将读锁请求设置为一个较低的值(例如10),那么如果读锁请求已经被传递给10个写锁请求,那么读锁请求可能会优先于挂起的写锁请求。通常这种行为不会发生,因为max_write_lock_count
默认值非常大。
语句将元数据逐个锁定,而不是同时锁定,并在此过程中执行死锁检测。
DML语句通常按照语句中提到表格的顺序获取锁。
DDL陈述,锁定表
此外,其他类似的语句尝试通过在名称顺序的明确命名的表上获取锁来减少并发DDL语句之间可能的死锁的数量。可以以不同的顺序获取锁定,用于隐式使用的表(例如也必须锁定的外键关系中的表)。
例如,重命名表
是一个DDL语句,以名称顺序获取锁:
这
重命名表
声明重命名TBLA.
到别的东西,并重命名tblc.
至TBLA.
:将表TBLA重命名为TBLD,TBLC到TBLA;
该语句按顺序(on)获取元数据锁
TBLA.
那tblc.
, 和TBLD.
(因为TBLD.
换tblc.
名字顺序):这种略有不同的陈述也重新组缩
TBLA.
到别的东西,并重命名tblc.
至TBLA.
:将表TBLA重命名为TBLB,TBLC到TBLA;
在本例中,该语句按顺序(on)获取元数据锁
TBLA.
那TBLB.
, 和tblc.
(因为TBLB.
前面tblc.
名字顺序):
两个陈述都获得了锁TBLA.
和tblc.
,以此顺序,但在以前或之后获取剩余表名上的锁定是否有所不同tblc.
.
当多个事务并发执行时,元数据锁的获取顺序可能会影响操作结果,如下面的示例所示。
从两个表开始X
和x_new
它们有相同的结构。三个客户端发出的语句涉及这些表:
客户端1:
锁表x写入,x_new写;
语句按名称顺序请求并获取写锁X
和x_new
.
客户2:
插入X值(1);
等待写入锁的语句请求和块X
.
客户端3:
将表x重命名为x_old,x_new到x;
语句按名称顺序请求独占锁X
那x_new
, 和x_old
,但街区等待锁定X
.
客户端1:
解锁表;
该声明释放了写入锁X
和x_new
.独家锁定请求X
Client 3的写锁请求优先级高于Client 2的写锁请求,因此Client 3获得了自己的锁onX
然后也在x_new
和x_old
,执行重命名,并释放其锁。客户2然后获取其锁定X
,执行插入操作,并释放锁。
锁定获取顺序导致重命名表
执行前插入
.的X
发生插入的是命名的表x_new
当客户端2发出插入并重命名为X
通过客户端3:
mysql>从x中选择*;+ ------ + |我|+ ------ + |1 |+ ------ + mysql> select * from x_old;空集(0.01秒)
现在开始与名为的表格X
和new_x
它们有相同的结构。同样,有三个客户端发出涉及这些表的语句:
客户端1:
锁表x写入,new_x写;
语句按名称顺序请求并获取写锁new_x
和X
.
客户2:
插入X值(1);
等待写入锁的语句请求和块X
.
客户端3:
将表X重命名为Old_x,new_x到x;
语句按名称顺序请求独占锁new_x
那old_x.
, 和X
,但街区等待锁定new_x
.
客户端1:
解锁表;
该声明释放了写入锁X
和new_x
.为了X
,唯一的待处理请求由客户端2,因此客户端2获取其锁定,执行插入,并释放锁定。为了new_x
,唯一待处理的请求是客户3,允许获取该锁(以及锁定old_x.
)。重命名操作仍然阻止锁定X
直到Client 2插入完成并释放它的锁。然后Client 3获得锁定X
,执行重命名,并释放其锁定。
在这种情况下,锁定采集顺序会导致插入
执行前重命名表
.的X
发生插入的是原始的X
,现在重命名为old_x.
通过重命名操作:
mysql>从x中选择*;空集(0.01秒)mysql> select * from old_x;+ ------ + |我|+ ------ + |1 |+ ------ +
如果在并发语句中的锁定采集顺序对操作结果中的应用程序有所不同,如前面的示例中,您可能能够调整表名以影响锁定采集的顺序。
必要时,元数据锁将延伸到由外键约束相关的表,以防止冲突的DML和DDL操作在相关表上同时执行。更新父表时,在更新外键元数据时,在子表上拍摄元数据锁定。外键元数据由子表拥有。
为确保事务序列化性,服务器不得允许一个会话在在另一个会话中明确或隐式启动的事务中未完成的表中使用的表中执行数据定义语言(DDL)语句。该服务器通过获取在事务中使用的表上使用的元数据锁而实现这一点,并在事务结束之前推迟锁定这些锁的释放。表上的元数据锁定可防止更改表的结构。此锁定方法具有暗示在交易结束之前不能在DDL语句中使用一次会话中的事务在DDL语句中使用的表。
这个原则不仅适用于事务性表,也适用于非事务性表。假设一个会话开始一个使用事务表的事务T.
和非讲台NT.
如下:
开始事务;SELECT * FROM t;SELECT * FROM nt;
该服务器在两者上保存元数据锁定T.
和NT.
直到交易结束。如果另一个会话在任何表上尝试DDL或写入锁定操作,则它会阻止,直到交易结束的元数据锁定释放。例如,如果它尝试了任何这些操作,则第二次会话块:
删除表T;改变表t ...;掉落表NT;改变表NT ......;锁定表T ...写;
相同的行为适用于此锁定表...阅读
.即,明确或隐式启动更新任何表(事务或非译员)块并被阻止的事务锁定表...阅读
那张桌子。
如果服务器获取用于在执行期间发生的语句但失败的语句的元数据锁,则不会提前释放锁定。锁定释放仍会延迟到事务的末尾,因为失败的语句被写入二进制日志,锁定保护日志一致性。
在自动提交模式下,每个语句实际上是一个完整的事务,因此为该语句获取的元数据锁只保留到语句结束。
在a期间获取的元数据锁准备
一旦制定了陈述,声明就会发布,即使在多账单交易中发生准备。
从MySQL 8.0.13开始,对于XA事务准备好
状态,Metadata锁在客户端断开连接和服务器重新启动,直到一个XA提交
或者XA回滚
执行。