MySQL 各锁粒度的读/写限制(完整权威版)
你想了解 MySQL 不同锁粒度下,对读操作和写操作的具体限制、互斥规则,同时我会补充锁的核心特性、适用场景和关联知识点,内容覆盖工作中所有常用场景。
核心前提:MySQL的锁粒度是 「全局锁」>「表级锁」>「行级锁」 ,粒度越大,加锁范围越广,并发能力越弱,加锁开销越小;粒度越小则相反。
一、前置核心概念(必读,理解基础)
1. 读/写操作定义
- 读操作:普通查询
SELECT(无锁读)、锁定读SELECT ... LOCK IN SHARE MODE/SELECT ... FOR UPDATE - 写操作:增删改
INSERT/UPDATE/DELETE、表结构修改ALTER TABLE等会修改数据/表结构的操作
2. 共享锁(S锁) & 排他锁(X锁) 基础规则
MySQL 所有锁的「读写互斥逻辑」,本质都基于这两个基础锁的规则,无例外:
✅ 共享锁(S锁):也叫「读锁」,多个事务可以同时加,互相兼容(你加我也能加);
✅ 排他锁(X锁):也叫「写锁」,独占锁,一个资源加了X锁后,其他事务既不能加S锁,也不能加X锁,完全互斥;
✅ 核心兼容规则:S与S兼容,S与X互斥,X与X互斥。
3. 存储引擎支持说明
- MyISAM:只支持「表级锁」,无行级锁,是 MySQL 早期的非事务引擎;
- InnoDB:支持全局锁、表级锁、行级锁(核心),是事务引擎,也是现在生产环境的默认选择,面试/工作核心考点;
- 全局锁:所有引擎都受其限制(粒度太大,作用于整个实例)。
二、全局锁(粒度最大:整个MySQL实例)
✅ 作用范围
对 整个MySQL数据库实例 加锁,加锁后所有数据库、所有表都会被锁定,是粒度最大的锁,没有更大的锁了。
✅ 锁类型
MySQL 全局锁只有 「全局只读锁」 一种形态(FLUSH TABLES WITH READ LOCK, FTWRL),本质是给整个实例加全局S锁,没有全局X锁(无实际使用场景)。
✅ 对「读/写」的严格限制【核心】
- 读操作限制:✅ 无任何限制,所有会话(事务)都可以执行
SELECT读操作,能正常读取所有表的数据; - 写操作限制:❌ 完全阻塞,所有写操作全部禁止,包括:
- 所有表的
INSERT/UPDATE/DELETE(DML); - 所有表的
ALTER TABLE(DDL); - 甚至包括表的创建/删除
CREATE TABLE/DROP TABLE; - 所有写请求会被阻塞排队,直到全局锁被释放(
UNLOCK TABLES)。
- 所有表的
✅ 核心特性
- 加锁/解锁开销极小,因为只需要对实例加一次锁;
- 并发能力最差,加锁期间整个库变成「只读库」;
- 不会产生死锁(粒度太大,无锁竞争的场景)。
✅ 典型应用场景
唯一核心场景:全库逻辑备份(不加全局锁的话,备份的库数据可能「不一致」,比如A表备份完,B表被修改了)。
三、表级锁(粒度第二:整张表)
✅ 作用范围
对 单张完整的数据表 加锁,锁定后,整张表的所有行都会被锁定,是 MySQL 中开销较小、加锁速度快的锁粒度。
✅ 锁类型(核心2种)
InnoDB/MyISAM 均支持,分为两种,严格遵循「S/X锁兼容规则」:
- 表共享读锁(表S锁):读锁,对整张表加的共享锁;
- 表排他写锁(表X锁):写锁,对整张表加的排他锁。
✅ 对「读/写」的严格限制【核心,分两种锁说明】
✔ 情况1:加了「表S锁」(对表加读锁)
- 读操作:✅ 所有会话都能读,无限制,多个会话可以同时加表S锁,互相兼容;
- 写操作:❌ 所有会话都不能写,不管是加锁的会话,还是其他会话,对该表的
INSERT/UPDATE/DELETE/ALTER全部阻塞,直到表S锁释放。
✔ 情况2:加了「表X锁」(对表加写锁)
- 读操作:❌ 除加锁会话外,其他所有会话都不能读,加锁的会话自己可以正常读;
- 写操作:❌ 除加锁会话外,其他所有会话都不能写,加锁的会话自己可以正常写;
核心总结:表X锁是「独占锁」,整张表被一个会话独占,其他会话读写全阻塞。
✅ 核心特性
- 加锁快、开销小,无死锁风险;
- 并发能力差(比全局锁好,比行级锁差),适合「全表批量操作」(比如批量更新全表数据);
- MyISAM 的默认锁机制,InnoDB 也支持,但 InnoDB 会尽量避免使用表级锁(优先行级锁)。
四、行级锁(粒度最小:单行/多行数据,InnoDB独有!重中之重)
✅ 作用范围
对 表中的某一行/多行数据 加锁,是 MySQL 中粒度最小的锁,也是 InnoDB 实现「高并发」的核心基础,面试必考、工作必用。
✅ 重要特性1:行级锁是 InnoDB独有的锁,MyISAM 不支持!
✅ 重要特性2:行级锁 依赖索引 实现!如果查询/更新时没有走索引,InnoDB 会「行锁升级为表锁」,等于整张表被锁定,这是生产环境「锁冲突」的高频坑点!
✅ 锁类型(核心2种)
同样遵循「S/X锁兼容规则」,只是锁定范围缩小到行,分为:
- 行共享读锁(行S锁):对某行数据加读锁,
SELECT ... LOCK IN SHARE MODE会触发; - 行排他写锁(行X锁):对某行数据加写锁,
INSERT/UPDATE/DELETE/SELECT ... FOR UPDATE会自动触发。
✅ 对「读/写」的严格限制【核心,分两种锁说明,重中之重】
✅ 核心前提:不同行的锁互不影响!互不影响!互不影响! 这是行级锁的灵魂,也是高并发的核心原因。比如对 id=1 的行加锁,id=2 的行完全不受限,其他会话可以随意读写id=2的行。
✔ 情况1:对某行加了「行S锁」(行读锁)
- 读操作:✅ 所有会话都能读这行数据,无限制,多个会话可以同时对这行加行S锁;
- 写操作:❌ 仅对「加锁的这一行」写操作阻塞,其他行的写操作完全正常;比如 id=1 加了行S锁,那么所有会话对 id=1 的
UPDATE/DELETE都会阻塞,对 id=2/3 的写操作不受限。
✔ 情况2:对某行加了「行X锁」(行写锁)
- 读操作:分两种情况(InnoDB核心考点,务必记住)
- 普通读
SELECT:✅ 无任何限制,能正常读取(InnoDB的「快照读」机制,基于MVCC实现,不用加锁,也不用等锁); - 锁定读
SELECT ... LOCK IN SHARE MODE/FOR UPDATE:❌ 阻塞,必须等行X锁释放后才能执行;
- 普通读
- 写操作:❌ 仅对「加锁的这一行」写操作阻塞,其他行的写操作完全正常;只有加锁的会话能对这行执行增删改,其他会话对这行的写操作全部排队等待。
✅ 核心特性
- 加锁慢、开销大(需要逐行加锁),可能产生死锁(多个会话互相持有对方需要的行锁);
- 并发能力最强,是生产环境高并发业务的首选锁粒度;
- 仅 InnoDB 支持,依赖事务和索引。
五、补充:意向锁(表级,InnoDB独有,行锁的「辅助锁」)
✅ 为什么要单独讲意向锁?
你大概率会疑惑:行级锁是锁行,为什么还要表级的意向锁?
答案:意向锁是为了「快速判断表中是否有行锁」,减少锁的判断开销。如果没有意向锁,当要给一张表加表级锁时,需要逐行检查是否有行锁,效率极低。
✅ 作用范围 & 类型
- 作用范围:表级锁,只作用于整张表;
- 锁类型:2种,都是「意向锁」,无实际读写限制,仅做判断:
- 意向共享锁(IS锁):事务给某行加「行S锁」之前,会自动先给表加IS锁;
- 意向排他锁(IX锁):事务给某行加「行X锁」之前,会自动先给表加IX锁。
✅ 核心规则(无读写限制,只有互斥规则)
- 意向锁之间 完全兼容:IS和IS、IS和IX、IX和IX都能共存,互不影响;
- 意向锁和「表级S/X锁」的互斥规则:
- 表S锁 与 IX锁 互斥(加了IX锁的表,不能加表S锁);
- 表X锁 与 IS/IX锁 都互斥(加了IS/IX锁的表,不能加表X锁);
- 对业务无感知:意向锁是 InnoDB 自动加、自动释放 的,无需手动操作,业务层完全感知不到。
六、所有锁粒度的「读写限制 & 核心属性」总结表(必收藏)
| 锁粒度 | 粒度大小 | 核心锁类型 | 读操作限制 | 写操作限制 | 并发能力 | 加锁开销 | 支持引擎 |
|---|---|---|---|---|---|---|---|
| 全局锁 | 最大 | 全局S锁 | 无限制,所有会话可正常读 | 完全阻塞,所有写操作排队 | 最差 | 最小 | 所有引擎 |
| 表级锁 | 中等 | 表S锁、表X锁 | 表S锁:无限制;表X锁:仅加锁会话可读 | 表S锁:全阻塞;表X锁:仅加锁会话可写 | 较差 | 较小 | MyISAM/InnoDB |
| 行级锁 | 最小 | 行S锁、行X锁 | 普通读无限制;锁定读在加X锁时阻塞 | 仅加锁行阻塞,其他行无限制 | 最好 | 最大 | 仅InnoDB |
| 意向锁 | 表级 | IS锁、IX锁 | 无任何读写限制 | 无任何读写限制 | - | 极小 | 仅InnoDB |
七、关键补充(生产环境避坑+面试高频考点)
✅ 1. 行锁的致命坑:无索引 → 行锁变表锁
InnoDB的行锁是基于索引的,如果你的SQL语句中,查询条件/更新条件没有用到索引(比如 UPDATE user SET name='test' WHERE age=20,age无索引),那么InnoDB会认为需要锁定整张表的所有行,此时行锁会自动升级为表锁,所有读写都会阻塞,并发直接崩盘!
✅ 2. 读操作的两种形态(InnoDB核心)
InnoDB的读操作分两种,这也是为什么「行X锁加了,还能正常SELECT」的原因:
- 快照读:普通
SELECT,基于MVCC实现,不加锁、不阻塞,读取的是数据的「快照版本」,是InnoDB的默认读方式; - 当前读:
SELECT ... LOCK IN SHARE MODE/SELECT ... FOR UPDATE/INSERT/UPDATE/DELETE,读取的是数据的「最新版本」,必须加锁,会被行X锁阻塞。
✅ 3. 锁粒度的核心权衡
没有最优的锁粒度,只有最合适的锁粒度:
- 粒度越大 → 加锁快、开销小、并发差,适合「全表批量操作」(比如全表更新、全库备份);
- 粒度越小 → 加锁慢、开销大、并发好,适合「高并发的单行操作」(比如电商下单、用户信息修改)。
总结(核心考点,一句话记住)
- 全局锁:全库只读,写全阻塞,粒度最大,并发最差;
- 表级锁:读共享,写独占,整张表锁定,并发一般;
- 行级锁:行粒度锁定,不同行互不影响,读无锁(快照读),写独占,并发最好,InnoDB核心;
- 核心规则:
S与S兼容,S与X互斥,X与X互斥,所有锁的读写限制都基于此; - 行锁依赖索引,无索引必升级为表锁,生产环境重中之重!
希望这份完整的内容能帮你彻底理清MySQL锁粒度的读写限制,如有疑问可以随时补充提问!

浙公网安备 33010602011771号