Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > mysql间隙锁

MySQL MVCC + 间隙锁(Gap Lock)完整讲解

作者:超梦dasgg

这篇文章给大家介绍MySQL MVCC+间隙锁(Gap Lock)完整讲解,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

默认前提:InnoDB 引擎、事务隔离级别 RR(可重复读,MySQL 默认),这两个机制都是 InnoDB 实现并发控制、解决幻读的核心。

一、MVCC 多版本并发控制

1. 作用

不用加锁实现读写互不阻塞:读不加锁、写加排他锁,大幅提升并发性能,同时实现 RR 隔离。

2. 核心隐藏字段(每条行记录自带)

  1. DB_TRX_ID:最近修改该行的事务 ID
  2. DB_ROLL_PTR:回滚指针,指向 undo log(版本链)
  3. DB_ROW_ID:无主键时隐藏主键

3. Undo Log 版本链

每次修改数据,不会直接覆盖原数据,而是把旧版本存入 undo log,通过 roll_ptr 串联成版本链表。 一条记录的多个历史版本,构成一条版本链。

4. Read View 读视图(RR 隔离核心)

事务执行第一次快照读时生成,用来判断当前版本是否可见,4 个关键字段:

  1. m_ids:当前活跃未提交事务集合
  2. min_trx_id:活跃事务最小 ID
  3. max_trx_id:下一个待分配事务 ID
  4. creator_trx_id:当前事务自己 ID

可见性规则(遍历版本链判断)

拿版本的 trx_id 和 ReadView 对比:

  1. trx_id == creator_trx_id:自己改的数据,可见
  2. trx_id < min_trx_id:事务已提交,可见
  3. trx_id > max_trx_id:事务启动晚于当前视图,不可见
  4. min_trx_id ≤ trx_id ≤ max_trx_id:
    • trx_id 在 m_ids 活跃集合:未提交,不可见
    • 不在 m_ids:已提交,可见

不满足就顺着 roll_ptr 找上一个历史版本,直到找到可见版本。

5. RC vs RR 的 MVCC 区别

6. MVCC 解决了什么问题

快照读下:

二、InnoDB 锁体系 + 间隙锁(Gap Lock)

1. 三类锁组合(RR 下当前读生效)

  1. 记录锁 Record Lock:锁住索引上存在的某一行
  2. 间隙锁 Gap Lock:锁住索引记录之间的空隙,阻止插入新数据,专门防幻读
  3. 临键锁 Next-Key Lock = Record + Gap:RR 默认加的锁,左开右闭区间 (a,b]

幻读定义:同一事务内多次当前读,中间其他事务插入新数据,第二次读多出数据。间隙锁锁空隙,不让别的事务插入,彻底杜绝幻读。

2. 间隙锁什么时候产生?

仅满足两个条件:

  1. 隔离级别 = RR(RC 无间隙锁,只会出现幻读)
  2. 当前读:update / delete / select ... for update / lock in share mode

3. 锁范围规则(基于索引,无索引退化成表锁)

场景 1:命中唯一索引,精准匹配一条完整记录

临键锁降级为 记录锁,不再加间隙锁 例:主键 id=10,select * from t where id=10 for update; 只锁 id=10 这一行,不锁间隙,其他事务可以插入 9、11。

场景 2:范围查询 / 不命中任何索引值 / 普通索引模糊匹配

临键锁(Next-Key),包含间隙,阻止插入 示例表主键:1,3,5,7 执行 where id <5 for update 锁定区间:(-∞,1], (1,3], (3,5] 间隙 (0,1)、(1,3)、(3,5) 全部锁住,其他事务不能插入 2、4,杜绝幻读。

场景 3:查询条件无索引

无法定位行,直接升级为 表级临键锁,整张表所有间隙全部锁住,并发极差。

4. 间隙锁特点

  1. 共享 / 排他间隙锁冲突规则:间隙锁之间互不阻塞 事务 A 加间隙锁 (3,5),事务 B 也可以加 (3,5) 间隙锁;只有插入操作会被间隙锁阻塞(插入意向锁冲突)。
  2. 只存在 RR 隔离级别;RC 全程没有间隙锁,允许幻读。
  3. 锁的是索引间隙,不是物理数据页。

5. 插入意向锁(Gap Intention Lock)

事务要插入数据时,先加插入意向间隙锁:表示 “我准备在这个间隙插入”。 如果该区间已有普通间隙锁,插入意向锁等待阻塞,实现间隙锁阻止插入的效果。

三、MVCC 和 间隙锁分工对比(重点区分)

维度MVCC间隙锁(临键锁)
作用对象快照读(普通 select)当前读(update/for update)
解决问题脏读、不可重复读当前读下的幻读
并发表现读写不阻塞写之间互相阻塞
锁机制无锁,靠 undo 版本链悲观锁,锁定索引间隙
RC 下是否存在存在不存在
RR 下是否存在存在存在

关键一句话总结

  1. MVCC 负责普通查询不加锁,保证快照读稳定可重复;
  2. 间隙锁(临键锁)负责写操作时锁住空隙,防止其他事务插入新数据,解决当前读幻读;
  3. 两者配合,让 InnoDB 在 RR 隔离下,既拥有高并发,又完美满足可重复读、无幻读。

四、高频面试延伸考点

  1. 为什么 RR 能解决幻读,RC 不行? RC 没有间隙锁,范围更新时其他事务可以插入新行,出现幻读;RR 当前读加临键锁锁住间隙,禁止插入。
  2. 唯一索引等值查询为什么间隙锁会降级? 唯一索引精准匹配只会命中一条记录,不存在新增插入产生幻读的可能,无需锁间隙,只加记录锁提升并发。
  3. MVCC 是乐观锁还是悲观锁? MVCC 是乐观并发控制;行锁 / 间隙锁属于悲观锁,两套机制独立工作。
  4. undo log 什么时候清理? 没有任何事务需要访问该历史版本时,purge 线程后台清理。

到此这篇关于MySQL MVCC + 间隙锁(Gap Lock)完整讲解的文章就介绍到这了,更多相关mysql间隙锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文