Jw
首页
技术
英语
首页
技术
英语
  • MySQL

    • MySQL 基础
    • 环境变量配置(PATH)
    • SQL 语法与分类
    • MySQL 数据类型
    • SQL - DDL 数据定义语言
    • SQL - DML 数据操作语言
    • SQL - DQL 数据查询语言
    • SQL - DCL 数据控制语言
    • MySQL 函数
    • SQL 约束
    • SQL 外键约束
    • 多表关系
    • 多表查询(连接查询)
    • 隐式内连接 vs 显式内连接
    • 子查询
    • 多表查询案例
    • 事务
    • 并发事务问题与隔离级别
    • MySQL 体系结构与存储引擎
    • 索引概述
    • 索引结构
    • 索引分类
    • 索引语法
    • SQL 性能分析
    • 索引使用
    • 索引设计原则
    • SQL 优化 - 插入数据与主键优化
    • SQL 优化 - order by 与 group by
    • SQL 优化 - limit / count / update
    • 视图
    • 存储过程
    • 存储过程 - 变量
    • 存储过程 - 流程控制、游标与条件处理
    • 存储函数
    • 触发器
    • 锁概述与全局锁
    • 表级锁
    • 行级锁
    • InnoDB 逻辑存储结构
    • InnoDB 架构
    • 事务原理(redo / undo log)
    • MVCC
    • MySQL 系统数据库
    • MySQL 常用工具
    • 数据备份与导入导出
    • 错误日志与二进制日志
    • 查询日志与慢查询日志
    • 主从复制 - 概述与原理
    • 主从复制 - 搭建
    • Mycat 配置
    • Mycat 垂直拆分与水平拆分
    • Mycat 分片规则
    • Mycat 管理与监控
    • Mycat 读写分离 - 一主一从
    • Mycat 读写分离 - 双主双从

表级锁

表级锁每次操作锁住整张表:粒度大、冲突概率最高、并发度最低。分为表锁、元数据锁(MDL)、意向锁三类。

一、介绍

  • 表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 应用在 MyISAM、InnoDB、BDB 等存储引擎中。

主要分为以下三类:

#类型作用
1表锁手动 LOCK TABLES,分表共享读锁、表独占写锁
2元数据锁(meta data lock,MDL)系统自动加锁,避免 DML 与 DDL 冲突
3意向锁让表锁不必逐行检查行锁,减少表锁的检查

演示用表:

CREATE TABLE score(
    id      INT PRIMARY KEY,
    name    VARCHAR(20),
    math    INT,
    english INT,
    chinese INT
);

INSERT INTO score VALUES (1,'Tom',67,88,95), (2,'Rose',23,66,90), (3,'Jack',56,98,76);

二、表锁

对于表锁,分为两类:表共享读锁(read lock)、表独占写锁(write lock)。

操作语法
加锁LOCK TABLES 表名... READ/WRITE
释放锁UNLOCK TABLES / 客户端断开连接

加锁后的行为

锁类型加锁会话自身其他会话
读锁 READ可读,不能写可读,写被阻塞
写锁 WRITE可读可写读、写都被阻塞

实测:读锁

-- 会话 A
LOCK TABLES score READ;
SELECT * FROM score;                       -- 自身可读 → 正常返回 3 行
UPDATE score SET math = 100 WHERE id = 2;  -- 自身不能写
-- ERROR 1099 (HY000): Table 'score' was locked with a READ lock and can't be updated
-- 会话 B
SELECT * FROM score;                       -- 可读 → 正常返回 3 行
UPDATE score SET math = 100 WHERE id = 2;  -- 写被阻塞
-- 一直等待;会话 A 执行 UNLOCK TABLES 后才成功
-- Query OK, 1 row affected (20.42 sec)

实测:写锁

-- 会话 A
LOCK TABLES score WRITE;
SELECT * FROM score;                        -- 自身可读 → 正常返回
UPDATE score SET chinese = 100 WHERE id = 1; -- 自身可写 → Query OK, 1 row affected
-- 会话 B
SELECT * FROM score;                        -- 读被阻塞(Ctrl+C 中止)
-- ERROR 1317 (70100): Query execution was interrupted
UPDATE score SET chinese = 100 WHERE id = 3;  -- 写同样被阻塞

读锁是共享的(别人还能读),写锁是排他的(别人读写都不行);LOCK TABLES 会一次性只锁列出的表,未列出的表在本会话也不可访问。

三、元数据锁(MDL)

  • MDL 加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。
  • 主要作用是维护表元数据的数据一致性:在表上有活动事务的时候,不可以对元数据进行写入操作 —— 即为了避免 DML 与 DDL 冲突,保证读写的正确性。
  • MySQL 5.5 中引入了 MDL:对一张表进行增删改查时加 MDL 读锁(共享);对表结构进行变更操作时加 MDL 写锁(排他)。
对应 SQL锁类型说明
LOCK TABLES xxx READ / WRITESHARED_READ_ONLY / SHARED_NO_READ_WRITE
SELECT、SELECT ... LOCK IN SHARE MODESHARED_READ与 SHARED_READ、SHARED_WRITE 兼容,与 EXCLUSIVE 互斥
INSERT、UPDATE、DELETE、SELECT ... FOR UPDATESHARED_WRITE与 SHARED_READ、SHARED_WRITE 兼容,与 EXCLUSIVE 互斥
ALTER TABLE ...EXCLUSIVE与其他的 MDL 都互斥

查看元数据锁

SELECT object_type, object_schema, object_name, lock_type, lock_duration
FROM performance_schema.metadata_locks;

实测:事务未提交时 DDL 被阻塞

-- 会话 A:开启事务并查询(此时表上还没有 java 列)
BEGIN;
SELECT * FROM score;

-- 会话 B:修改表结构 → 阻塞,直到会话 A 提交
ALTER TABLE score ADD COLUMN java INT;
-- Query OK, 0 rows affected (1 min 18 sec)

会话 A 未提交时查看 metadata_locks:

+-------------+---------------+-------------+-------------+---------------+
| object_type | object_schema | object_name | lock_type   | lock_duration |
+-------------+---------------+-------------+-------------+---------------+
| TABLE       | db01          | score       | SHARED_READ | TRANSACTION   |
+-------------+---------------+-------------+-------------+---------------+

普通 SELECT 也会持有 SHARED_READ 的 MDL;只要事务不提交,ALTER TABLE 想拿 EXCLUSIVE 就得一直等 —— 长事务会拖住所有 DDL。

四、意向锁

为了避免 DML 在执行时,加的行锁与表锁的冲突,InnoDB 引入了意向锁,使得表锁不用检查每行数据是否加锁,用意向锁减少表锁的检查。

意向锁由什么语句添加与表锁的关系
意向共享锁(IS)SELECT ... LOCK IN SHARE MODE与表锁共享锁(READ)兼容,与表锁排它锁(WRITE)互斥
意向排他锁(IX)INSERT、UPDATE、DELETE、SELECT ... FOR UPDATE与表锁共享锁(READ)及排它锁(WRITE)都互斥

兼容性矩阵

当前锁 \ 请求锁表共享读锁 READ表独占写锁 WRITE
意向共享锁 IS兼容互斥
意向排他锁 IX互斥互斥

意向锁之间不会互斥。

查看意向锁及行锁的加锁情况

SELECT object_schema, object_name, index_name, lock_type, lock_mode, lock_data
FROM performance_schema.data_locks;

实测:IS + 行级共享锁

-- 会话 A
BEGIN;
SELECT * FROM score WHERE id = 1 LOCK IN SHARE MODE;
+---------------+-------------+------------+-----------+---------------+-----------+
| object_schema | object_name | index_name | lock_type | lock_mode     | lock_data |
+---------------+-------------+------------+-----------+---------------+-----------+
| db01          | score       | NULL       | TABLE     | IS            | NULL      |  ← 意向共享锁
| db01          | score       | PRIMARY    | RECORD    | S,REC_NOT_GAP | 1         |  ← 行级共享锁
+---------------+-------------+------------+-----------+---------------+-----------+

实测:IX + 行级排他锁

-- 会话 A
BEGIN;
UPDATE score SET math = 66 WHERE id = 1;
+---------------+-------------+------------+-----------+---------------+-----------+
| object_schema | object_name | index_name | lock_type | lock_mode     | lock_data |
+---------------+-------------+------------+-----------+---------------+-----------+
| db01          | score       | NULL       | TABLE     | IX            | NULL      |  ← 意向排他锁
| db01          | score       | PRIMARY    | RECORD    | X,REC_NOT_GAP | 1         |  ← 行级排他锁
+---------------+-------------+------------+-----------+---------------+-----------+

加了行锁,表上就会自动出现对应的意向锁;别的会话想 LOCK TABLES ... WRITE 时,看一眼表上的意向锁就知道「表里已经有行锁了」,不必逐行扫描。

速查

-- 表锁:加读锁 → 自身可读不可写;其他会话可读,写阻塞
LOCK TABLES score READ;
-- 表锁:加写锁 → 自身可读可写;其他会话读写都阻塞
LOCK TABLES score WRITE;
-- 释放表锁 → 会话断开也会自动释放
UNLOCK TABLES;

-- 查看元数据锁(MDL)→ 普通 SELECT 持 SHARED_READ,DDL 需要 EXCLUSIVE
SELECT object_type, object_schema, object_name, lock_type, lock_duration
FROM performance_schema.metadata_locks;

-- 查看意向锁与行锁 → TABLE 行是意向锁,RECORD 行是行锁
SELECT object_schema, object_name, index_name, lock_type, lock_mode, lock_data
FROM performance_schema.data_locks;

-- 意向共享锁(IS)+ 行级共享锁(S,REC_NOT_GAP)
BEGIN;
SELECT * FROM score WHERE id = 1 LOCK IN SHARE MODE;

-- 意向排他锁(IX)+ 行级排他锁(X,REC_NOT_GAP)
BEGIN;
UPDATE score SET math = 66 WHERE id = 1;
场景关键点
要锁住整张表做维护LOCK TABLES 表名 READ/WRITE,用完 UNLOCK TABLES
读锁 vs 写锁读锁共享(别人可读)、写锁排他(别人读写都阻塞)
DDL 被卡住长事务持有的 MDL 读锁未释放;等它 COMMIT 后才拿到 EXCLUSIVE
只有行锁,表锁如何知道行锁会连带自动加意向锁(IS / IX),供表锁快速判断
查看锁情况MDL 看 performance_schema.metadata_locks;意向锁与行锁看 performance_schema.data_locks

相关

  • 锁概述与全局锁:锁的分类与全局锁
  • 行级锁:行锁、间隙锁、临键锁
  • SQL 优化 - limit / count / update:UPDATE 不走索引时行锁升级为表锁
  • MySQL 体系结构与存储引擎:各存储引擎支持的锁
最近更新: 2026/10/14 21:03
Contributors: liujw
Prev
锁概述与全局锁
Next
行级锁