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锁(无实际使用场景)。

✅ 对「读/写」的严格限制【核心】

  1. 读操作限制:✅ 无任何限制,所有会话(事务)都可以执行 SELECT 读操作,能正常读取所有表的数据;
  2. 写操作限制:❌ 完全阻塞所有写操作全部禁止,包括:
    • 所有表的 INSERT/UPDATE/DELETE(DML);
    • 所有表的 ALTER TABLE(DDL);
    • 甚至包括表的创建/删除 CREATE TABLE/DROP TABLE
    • 所有写请求会被阻塞排队,直到全局锁被释放(UNLOCK TABLES)。

✅ 核心特性

  • 加锁/解锁开销极小,因为只需要对实例加一次锁;
  • 并发能力最差,加锁期间整个库变成「只读库」;
  • 不会产生死锁(粒度太大,无锁竞争的场景)。

✅ 典型应用场景

唯一核心场景:全库逻辑备份(不加全局锁的话,备份的库数据可能「不一致」,比如A表备份完,B表被修改了)。


三、表级锁(粒度第二:整张表)

✅ 作用范围

单张完整的数据表 加锁,锁定后,整张表的所有行都会被锁定,是 MySQL 中开销较小、加锁速度快的锁粒度。

✅ 锁类型(核心2种)

InnoDB/MyISAM 均支持,分为两种,严格遵循「S/X锁兼容规则」:

  1. 表共享读锁(表S锁):读锁,对整张表加的共享锁;
  2. 表排他写锁(表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锁兼容规则」,只是锁定范围缩小到,分为:

  1. 行共享读锁(行S锁):对某行数据加读锁,SELECT ... LOCK IN SHARE MODE 会触发;
  2. 行排他写锁(行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核心考点,务必记住
    1. 普通读 SELECT:✅ 无任何限制,能正常读取(InnoDB的「快照读」机制,基于MVCC实现,不用加锁,也不用等锁);
    2. 锁定读 SELECT ... LOCK IN SHARE MODE/FOR UPDATE:❌ 阻塞,必须等行X锁释放后才能执行;
  • 写操作:❌ 仅对「加锁的这一行」写操作阻塞,其他行的写操作完全正常;只有加锁的会话能对这行执行增删改,其他会话对这行的写操作全部排队等待。

✅ 核心特性

  • 加锁慢、开销大(需要逐行加锁),可能产生死锁(多个会话互相持有对方需要的行锁);
  • 并发能力最强,是生产环境高并发业务的首选锁粒度;
  • 仅 InnoDB 支持,依赖事务和索引。

五、补充:意向锁(表级,InnoDB独有,行锁的「辅助锁」)

✅ 为什么要单独讲意向锁?

你大概率会疑惑:行级锁是锁行,为什么还要表级的意向锁?
答案:意向锁是为了「快速判断表中是否有行锁」,减少锁的判断开销。如果没有意向锁,当要给一张表加表级锁时,需要逐行检查是否有行锁,效率极低。

✅ 作用范围 & 类型

  • 作用范围:表级锁,只作用于整张表;
  • 锁类型:2种,都是「意向锁」,无实际读写限制,仅做判断:
    1. 意向共享锁(IS锁):事务给某行加「行S锁」之前,会自动先给表加IS锁
    2. 意向排他锁(IX锁):事务给某行加「行X锁」之前,会自动先给表加IX锁

✅ 核心规则(无读写限制,只有互斥规则)

  1. 意向锁之间 完全兼容:IS和IS、IS和IX、IX和IX都能共存,互不影响;
  2. 意向锁和「表级S/X锁」的互斥规则:
    • 表S锁 与 IX锁 互斥(加了IX锁的表,不能加表S锁);
    • 表X锁 与 IS/IX锁 都互斥(加了IS/IX锁的表,不能加表X锁);
  3. 对业务无感知:意向锁是 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. 锁粒度的核心权衡

没有最优的锁粒度,只有最合适的锁粒度

  • 粒度越大 → 加锁快、开销小、并发差,适合「全表批量操作」(比如全表更新、全库备份);
  • 粒度越小 → 加锁慢、开销大、并发好,适合「高并发的单行操作」(比如电商下单、用户信息修改)。

总结(核心考点,一句话记住)

  1. 全局锁:全库只读,写全阻塞,粒度最大,并发最差;
  2. 表级锁:读共享,写独占,整张表锁定,并发一般;
  3. 行级锁:行粒度锁定,不同行互不影响,读无锁(快照读),写独占,并发最好,InnoDB核心;
  4. 核心规则:S与S兼容,S与X互斥,X与X互斥,所有锁的读写限制都基于此;
  5. 行锁依赖索引,无索引必升级为表锁,生产环境重中之重!

希望这份完整的内容能帮你彻底理清MySQL锁粒度的读写限制,如有疑问可以随时补充提问!

posted @ 2026-01-17 15:31  先弓  阅读(0)  评论(0)    收藏  举报