Mysql-元数据锁

114 阅读2分钟

MDL锁简述

MySQL5.5版本开始引入了MDL锁, 用来保护表的元数据信息, 其主要解决了 2个问题:

  1. 事务隔离问题---DDl操作对其他事务的影响
  2. 数据复制的问题---控制不同线程之间的执行顺序问题

事务隔离问题

时间session1session2
begin;
T1select * from t;
T2drop table t;
T3select * from t
end

1.在不加锁的情况下,T3时刻会出现 table doesn't exist

为了解决1这个问题,DDL对这个操作的影响,在T1时刻加上MDL元数据锁,在T2时刻的操作会被阻塞

数据的复制问题

时间session1session2
begin;
T1insert into t(c1, c2) values(v1, v2);
T2alter table t drop column c2;--写入 binlog 1
T3end; --写入binlog 2
binglog 传入备库后, 先执行了 binlog 1, 再binlog 2, 因执行顺变更导致异常。

在T1时刻加MDL锁,可以解决从库回放,执行顺序异常的问题

MDL基础

MDL核心数据结构

被加锁对像(enum_mdl_namespace)

锁持续时长(enum_mdl_duration)

锁的具体类型(enum_mdl_type)


每次申请锁时都需要包含这三个类目

被加锁对像锁持续时长锁的具体类型

截屏2024-07-25 00.18.24.png

根据类型主要分为八小类,根据性质分为两小类(范围,对象)

范围类型的锁:主要控制公共资源,控制他们的执行顺序


截屏2024-07-25 00.23.44.png

截屏2024-07-25 00.24.31.png

MDL锁的兼容矩阵

范围锁的兼容矩阵

截屏2024-07-25 00.27.27.png

对象锁的兼容矩阵

截屏2024-07-25 00.27.55.png

请求/释放流程

请求锁兼容性检查

  1. 检查请求锁是否与已经存在的活跃锁冲突, 若冲突, 则等待
  2. 检查请求锁是否与已经存在的等待锁冲突, 若冲突, 则等待
  3. 请求锁成功

释放锁时机

  1. 语句执行结束后,释放STAMENT类型的锁
  2. 事务提交时, 先请求COMMIT类型 后释放COMMIT类型锁
  3. 事务提交后, 释放TRANSACTION类型的锁

MDL锁示示例


FTWRL 操作MDL锁流程

FTWRL(flush tables with read lock;)作用是对整个数据库实例加锁, 加锁后整个实例 处于只读状态。 FTWRL主要执行了3个操作:

  1. 上全局读锁【GLOBAL:MDL_EXPLICIT:S】
  2. 清理表缓存 【 关闭表的文件描述符 】
  3. 上全局COMMIT锁【COMMIT:MDL_EXPLICIT:S】
  4. unlock 后释放 GLOBAL 锁和 COMMIT 锁

SELECT 语句操作MDL锁流程

截屏2024-07-25 20.57.31.png

opening tables阶段

a) 请求: [TABLE:MDL_TRANSACTION:MDL_SHARED_READ]

事务提交阶段

a) 释放: [TABLE:MDL_TRANSACTION:MDL_SHARED_READ]

截屏2024-07-25 20.59.12.png

截屏2024-07-25 20.59.36.png

DML 语句操作MDL锁流程

截屏2024-07-25 21.00.02.png

截屏2024-07-25 21.00.43.png

截屏2024-07-25 21.01.01.png

截屏2024-07-25 21.01.26.png

DDL 语句操作MDL锁流程

截屏2024-07-25 21.02.07.png

截屏2024-07-25 21.02.17.png

截屏2024-07-25 21.02.46.png

截屏2024-07-25 21.03.33.png