MDL锁简述
MySQL5.5版本开始引入了MDL锁, 用来保护表的元数据信息, 其主要解决了 2个问题:
- 事务隔离问题---DDl操作对其他事务的影响
- 数据复制的问题---控制不同线程之间的执行顺序问题
事务隔离问题
| 时间 | session1 | session2 |
|---|---|---|
| begin; | ||
| T1 | select * from t; | |
| T2 | drop table t; | |
| T3 | select * from t | |
| end |
1.在不加锁的情况下,T3时刻会出现 table doesn't exist
为了解决1这个问题,DDL对这个操作的影响,在T1时刻加上MDL元数据锁,在T2时刻的操作会被阻塞
数据的复制问题
| 时间 | session1 | session2 |
|---|---|---|
| begin; | ||
| T1 | insert into t(c1, c2) values(v1, v2); | |
| T2 | alter table t drop column c2;--写入 binlog 1 | |
| T3 | end; --写入binlog 2 | |
| binglog 传入备库后, 先执行了 binlog 1, 再binlog 2, 因执行顺变更导致异常。 |
在T1时刻加MDL锁,可以解决从库回放,执行顺序异常的问题
MDL基础
MDL核心数据结构
被加锁对像(enum_mdl_namespace)
锁持续时长(enum_mdl_duration)
锁的具体类型(enum_mdl_type)
每次申请锁时都需要包含这三个类目
| 被加锁对像 | 锁持续时长 | 锁的具体类型 |
|---|
根据类型主要分为八小类,根据性质分为两小类(范围,对象)
范围类型的锁:主要控制公共资源,控制他们的执行顺序
MDL锁的兼容矩阵
范围锁的兼容矩阵
对象锁的兼容矩阵
请求/释放流程
请求锁兼容性检查
- 检查请求锁是否与已经存在的活跃锁冲突, 若冲突, 则等待
- 检查请求锁是否与已经存在的等待锁冲突, 若冲突, 则等待
- 请求锁成功
释放锁时机
- 语句执行结束后,释放STAMENT类型的锁
- 事务提交时, 先请求COMMIT类型 后释放COMMIT类型锁
- 事务提交后, 释放TRANSACTION类型的锁
MDL锁示示例
FTWRL 操作MDL锁流程
FTWRL(flush tables with read lock;)作用是对整个数据库实例加锁, 加锁后整个实例 处于只读状态。 FTWRL主要执行了3个操作:
- 上全局读锁【GLOBAL:MDL_EXPLICIT:S】
- 清理表缓存 【 关闭表的文件描述符 】
- 上全局COMMIT锁【COMMIT:MDL_EXPLICIT:S】
- unlock 后释放 GLOBAL 锁和 COMMIT 锁
SELECT 语句操作MDL锁流程
opening tables阶段
a) 请求: [TABLE:MDL_TRANSACTION:MDL_SHARED_READ]
事务提交阶段
a) 释放: [TABLE:MDL_TRANSACTION:MDL_SHARED_READ]