MySQL | 进阶-锁

本文更新于 2026-04-05

锁是数据库引擎用来管理对共享资源并发访问的机制,旨在保证事务的隔离性(Isolation)和一致性(Consistency)

锁的粒度 (Lock Granularity)

锁定的资源范围大小决定了系统的并发度

粒度等级描述特点
行级锁 (Row Lock)锁定单行记录。并发度最高,但加锁开销大(消耗内存多)。
页级锁 (Page Lock)锁定一组相邻的数据页。介于行锁与表锁之间(常见于 BDB 存储引擎)。
表级锁 (Table Lock)锁定整张表。开销小,加锁快,但并发度低(会导致大量阻塞)。

全局锁

全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。

其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性

  • 功能:让整个库处于只读状态。
  • 受限操作
    • 数据更新语句(数据的增删改)。
    • 数据定义语句(建表、修改表结构等)。
    • 更新类事务的提交语句
	FLUSH TABLES WITH READ LOCK;
	
	UNLOCK TABLES;
  • 特点: 数据库中加全局锁,是一个比较重的操作,存在以下问题:
    • 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆

    • 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。

–single-transaction

如果使用的引擎支持 事务(如 InnoDB,在使用 mysqldump 时可以使用参数 --single-transaction

  • 原理:在导数据之前就会启动一个事务,确保拿到一致性视图(Read View)。

  • 优势:由于 MVCC(多版本并发控制)的支持,数据库在备份期间依然可以正常更新数据,不会阻塞业务


表级锁

MySQL 的表级锁开销小,加锁快,不会出现死锁,但锁冲突的概率最高,并发度也最低。

表锁 (Table Lock)

显式加锁语法:

  • 加锁:lock tables 表名 read/write;
  • 释放:unlock tables;(或客户端断开连接)
锁类型描述
表共享读锁 (Read Lock)共享锁。所有客户端(包括自己)只能读,不能写。
表独占写锁 (Write Lock)独占锁。只有当前客户端可以读写,其他客户端被阻塞。

元数据锁 (Metadata Lock, MDL)

MDL 是隐式加锁的,不需要显式调用。 它的作用是防止 DDL(结构变更)与 DML(数据增删改)之间的冲突。

  • 对表做 DML 操作时:自动加 MDL 读锁(共享),不影响多个线程同时增删改查。
  • 对表做 DDL 操作时:自动加 MDL 写锁(排他),此时会阻塞所有的增删改查。

风险点:给大表加字段时,如果有一个长查询在运行,MDL 写锁会排队,进而导致后续所有的查询和更新都被堵住,甚至拖垮整个数据库。

意向锁 (Intention Lock)

意向锁是为了解决“行锁”与“表锁”共存时的效率问题。

  • 意向共享锁 (IS):事务准备给某些行加读锁前,先给表加 IS。

    • 与表锁共享锁(read)兼容,与表锁排他锁(write)互斥。
    • 执行 SELECT ... FOR SHARE 前自动加。
  • 意向排他锁 (IX):事务准备给某些行加写锁前,先给表加 IX。

    • 与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。
    • 执行 INSERT/UPDATE/DELETE 前自动加。
锁类型IS (意向共享)IX (意向排他)S (表级共享)X (表级排他)
IS兼容兼容兼容冲突
IX兼容兼容冲突冲突
S兼容冲突兼容冲突
X冲突冲突冲突冲突
核心意义:当你想加表锁(如 lock tables write)时,不需要逐行检查是否有行锁,直接看表上是否有意向锁即可,极大提高了性能。

[!tip] 解释 意向锁就像是酒店大堂的状态指示牌。如果没有它,你想包下整个酒店(表锁),得挨个敲门看有没有人住(行锁);有了它,你看一眼前台的登记簿(意向锁)就全明白了。

AUTO-INC 锁

这是一种特殊的表级锁,主要用于处理带有 AUTO_INCREMENT 列的表。

  • 当插入数据时,会加一个表级的 AUTO-INC 锁来获取自增值。
  • 在高并发插入场景下,这可能成为性能瓶颈(现代 MySQL 可以通过 innodb_autoinc_lock_mode 参数进行优化,使用轻量级互斥锁代替)。

行级锁

行级锁是 MySQL 中锁粒度最小的一种锁,主要由 InnoDB 存储引擎实现

它的特点是锁冲突概率最低,并发处理能力最强,但开销相对较大,且可能会出现死锁

锁类型名称锁定范围作用支持
Record Lock记录锁仅锁定单个索引记录。防止其他事务修改或删除该行。在RC,RR隔离级别下都支持
Gap Lock间隙锁锁定索引记录之间的间隙(不含记录本身)。防止其他事务在间隙内插入数据,解决幻读在RR隔离级别下支持
Next-Key Lock临键锁记录锁 + 间隙锁的组合。(锁住数据及前面的间隙)锁定一个范围,并锁定记录本身。InnoDB 默认的锁算法。

行锁

行锁分类

行锁在逻辑上主要分为两类:

  • 共享锁 (S 锁 / Shared Lock):又称读锁。允许事务读取一行数据。多个事务可以同时持有同一行的 S 锁。

    • 特点:兼容 S 锁,冲突 X 锁。
  • 排他锁 (X 锁 / Exclusive Lock):又称写锁。允许事务删除或更新一行数据。当一个事务持有 X 锁时,其他事务无法再对该行加任何锁。

    • 特点:冲突一切锁(包括 S 和 X)。
SQL 语句行锁类型说明
INSERT ...排他锁 (X)自动加锁。
UPDATE ...排他锁 (X)自动加锁。
DELETE ...排他锁 (X)自动加锁。
SELECT (正常)不加任何锁基于 MVCC 实现的快照读,不阻塞其他事务。
SELECT ... LOCK IN SHARE MODE共享锁 (S)需要手动在 SELECT 之后添加(兼容 S,互斥 X)。
SELECT ... FOR UPDATE排他锁 (X)需要手动在 SELECT 之后添加(互斥 S 和 X)。

[!TIPS] InnoDB 的行锁是通过给索引上的索引项加锁来实现的,而不是针对记录本身。 这意味着:如果你的 SQL 没有走索引,行锁就会升级为表锁。

间隙锁和临键锁

在 InnoDB 的 可重复读 (RR) 隔离级别下,间隙锁和临键锁是解决 幻读 (PR) 的核心机制。它们都是行级锁的变体,但是锁定的范围不同

间隙锁 (Gap Lock)

间隙锁锁定的不是记录本身,而是两条索引记录之间的“间隙”,或者是第一条记录之前、最后一条记录之后的空间。

  • 目的:防止其他事务在间隙中插入(INSERT)新数据,从而避免幻读。

  • 特性

    • 间隙锁之间是兼容的。一个事务持有的间隙锁不会阻止另一个事务在同一个间隙上获取间隙锁。

    • 它们唯一的冲突点是:防止其他事务插入数据

  • 示例

    假设表中 id 有 1, 5, 10。执行 SELECT * FROM t WHERE id = 3 FOR UPDATE;。 由于 id=3 不存在,InnoDB 会在 (1, 5) 这个间隙加锁。此时,任何想插入 id=2, 3, 4 的操作都会被阻塞。


临键锁 (Next-Key Lock)

临键锁是 记录锁 (Record Lock)间隙锁 (Gap Lock) 的组合。它既锁定索引记录本身,也锁定记录之前的间隙。

  • 公式:Next-Key Lock = Gap Lock + Record Lock。

  • 范围:默认是左开右闭区间。

  • 默认机制:InnoDB 在 RR 隔离级别下,对行扫描时默认加的就是 Next-Key Lock。

  • 示例

    假设表中 id 有 1, 5, 10。执行范围查询 WHERE id > 5 AND id <= 10 FOR UPDATE。 临键锁会锁定区间 (5, 10]。这包括了间隙 (5, 10) 和记录 id=10 本身。


锁的退化规则 (优化)

为了提高并发性能,InnoDB 在某些特定条件下会将临键锁“降级”:

  1. 唯一索引等值查询(记录存在): 当使用主键或唯一索引进行等值查询,且记录确实存在时,Next-Key Lock 会退化为 记录锁 (Record Lock)

    • 原因:既然记录是唯一的且已存在,就不可能再插入相同的记录,没必要锁间隙。
  2. 唯一索引等值查询(记录不存在): 当查询的记录不存在时,Next-Key Lock 会退化为 间隙锁 (Gap Lock)

    • 范围:锁定该值所在的那个间隙。
  3. 非唯一索引(普通索引)查询: 即便命中记录,InnoDB 也会在记录两边加锁(Next-Key Lock 加上右侧的 Gap Lock),以确保不会有新的相同索引值插入。


总结对比

锁类型锁定对象包含记录本身主要作用
记录锁 (Record Lock)单行记录防止其他事务修改或删除该行
间隙锁 (Gap Lock)索引之间的间隙防止其他事务插入数据,解决幻读
临键锁 (Next-Key Lock)间隙 + 记录RR 级别下的默认锁,结合了前两者优点

核心提示:间隙锁和临键锁只在 可重复读 (RR) 或更严苛的隔离级别下生效。在 读已提交 (RC) 级别下,间隙锁会被禁用(除非涉及外键约束或重复键检查)。

今日访问 ... 次 | 今日访客 ... 人 | 本页阅读 ...
小站已萌萌哒运行了 0 0 0
已累计耕耘 33 篇博文 · 共 115.17k 个字
总访问量 ...
备案图标 豫公网安备41019702004633号