【MySQL】MySQL中的MVCC是什么?它与隔离级别有什么关系?

1、MVCC是什么?

MVCC的核心思想:读不加锁,读写不冲突,通过数据的多个版本实现并发控制

它的实现依赖三个东西:

1、隐藏字段

每行数据有DB_TRX_ID (最近修改该行的事务ID ),DB_ROLL_PTR(回滚指针)

2.Undo Log 版本链

记录数据的历史版本,构成版本链

3.Read View

事务快照,决定当前事务能看到哪些版本

2、MVCC如何工作?

1.版本链

每次更新一行数据时,InnoDB会:

1.把旧版本写入Undo Log

2.新版本指向旧版本(通过回滚指针 )

3.形成一条版本链

bash 复制代码
当前版本→上个版本→更早版本

2.Read View

事务开始读取时,生成一个Read View,包含:

  • m_ids: 当前活跃事务ID 集合
  • min_trx_id:活跃事务中的最小ID
  • max_trx_id:下一个即将分配的事务ID
  • **creator_trx_id:**当前事务自己的ID

然后沿着版本链,按规则判断哪个版本对应当前事务可见。

3.核心关系:不同隔离级别,Read View 生成时机不同

这是理解 MVCC与事务隔离级别关系最关键的一部分

RU 读未提交

基本不用MVCC ,直接读最新版本

  • 不生成Read View
  • 直接读取当前最新数据,不管是否已提交
  • 所以会出现脏读

RC 读已提交

每次SELECT 都生成一个新的Read View

这意味着:

  • 每次查询都能看到别的事务最新提交的数据
  • 所以同一个事务里两次查询,结果可能不同 ,造成不可重复读

RR 可重复读

只在第一次SELECT时 生成Read View ,之后复用同一个

这意味着:

  • 整个事务期间,看到的都是同一个快照
  • 别的事务提交了更新,也看不到,这样就避免了不可重复读

Serializable 串行化

MVCC 退化为基于锁的并发控制

  • 所有SELECT 自动加 lock in share mode
  • 读写相互阻塞
  • MVCC的快照基本不再使用

4、MVCC能解决什么,不能解决什么

可以解决:

  • 脏读:通过 版本链+Read View 只读 已提交的版本
  • 不可重复读:RR 级别复用 Read View,保持快照一致
  • 普通的并发性能:读不加锁,读写不阻塞

不能完全解决的:

  • 幻读: MVCC的快照只能保证读到的行不变 ,但不能阻止别的事务插入新的行

5、那幻读怎么办? MVCC+锁 一起上!

RR 隔离级别下,InnoDB用 MVCC+Next-Key Lock 组合拳来对付幻读

场景:

普通SELECT 快照读

MVCC,读历史快照,看不到新插入的行

SELECT ... FOR UPDATE 当前读

Next-Key Lock,锁住间隙,阻止插入

UPDATE/DELETE 当前读

Next-Key Lock 同样锁间隙

所以:

MVCC 负责快照读的一致性 ,Next-Key Lock 负责当前读时防止幻读

6、总结

MVCC是InnoDB实现事务隔离的底层机制

不同隔离级别的本质区别在于Read View的生成时机不同
RC读已提交 每次查询都生成新的Read View
RR可重复读 只生成一次并复用

MVCC负责快照读的一致性 ,配合Next-Key Lock 解决当前读的幻读问题

相关推荐
lsylalalala1 小时前
mysql-索引1
数据库·mysql
2501_937860944 小时前
MySQL表的操作:创建、查看、修改、删除完整实战
android·数据库·mysql
奇特認8 小时前
mysql 集群技术 3.高可用之 MHA
数据库·mysql
Blossom i14 小时前
大数据预处理与采集实验一:使用Python操作MySQL数据库
数据库·mysql
InfinitePlus14 小时前
Docker MySQL搭建一主一从
mysql·docker
坐吃山猪16 小时前
Docker07-MySQL
mysql·docker·容器
少晓年17 小时前
从 MySQL 迁移到人大金仓 KingbaseES:完整指南与实践
数据库·mysql
Zhu75819 小时前
使用helm在k8s集群部署MySQL单实例,支持当前所有主版本的最新子版本
mysql·adb·kubernetes
灯澜忆梦1 天前
【MySQL11】进阶篇 | 索引_#3使用规则
数据库·sql·mysql·性能优化
wWYy.1 天前
Mysql:有哪些锁?
数据库·mysql