深入理解MySQL中的MVCC(多版本并发控制)

在MySQL中,MVCC是一种用于提供并发控制的技术,它允许数据库系统在事务并发执行的情况下保持数据的一致性,同时提高了数据库的并发性能。MVCC背后的理念是允许每个事务可以看到一个一致性的快照,从而避免了读取操作被写入操作所阻塞的情况。不用加锁,解决多并发场景下的快照读问题

1 MVCC的原理

MVCC的核心思想是为每个数据行保存其在不同时间点的版本,并通过版本号或时间戳来标识这些版本。当一个事务开始时,MySQL会为该事务创建一个独立的事务ID,并利用这个ID去获取数据的一致性快照。

  • Undo日志:在MySQL中,MVCC的实现依赖于undo日志(也称为回滚日志)。当某个事务对数据进行修改时,MySQL不会立即覆盖原始数据,而是将修改前的原始数据保存到undo日志中。这样,其他事务仍然可以访问到这个数据的旧版本,从而实现了数据的多版本管理。
  • ReadView:每个事务在启动时都会创建一个ReadView,这个视图通过检查undo日志中的信息和事务的时间戳来确定哪些数据版本对于当前事务是可见的。这样,对于已提交的数据版本,ReadView会返回最新的版本,对于未提交的数据版本,ReadView则会返回旧的版本或者忽略这些数据。

2 当前读和快照读

2.1 当前读

查询当前已提交最新的数据

  • SELECT LOCK IN SHARE MODE;(共享锁)
  • SELECT FOR UPDATE;(排它锁)
  • UPDATE(排它锁)
  • DELETE(排它锁)
  • INSERT(排它锁)
  • 串行化事务隔离级别

2.2 快照读

普通的select查询,通过MVCC进行版本链查找就叫快照读

3 版本链

3.1 什么是版本链

首先聚簇索引的叶子节点存储数据包括两个隐藏字段:trx_id(事务ID)、roll_pointer(回滚指针)

  • trx_id(事务ID):记录的是修改当前这行数据的事务ID
  • roll_pointer(回滚指针):记录该行数据上个版本的地址

因此版本链其实就是由回滚指针(roll_pointer)串起来的该行数据对应的各个版本。

3.2 read view

MySQL中的Read View(读视图)是多版本并发控制(MVCC)机制的一部分。在多用户并发访问数据库时,read view 能够确保每个用户看到的数据都是一致的,避免了脏读、不可重复读等问题。

read view中四个核心参数:

  • m_ids:当前活跃事务ID列表
  • min_trx_id:活跃事务最小ID
  • max_trx_id:下一个事务ID
  • creator_trx_id:当前事务ID

如何判断版本链中可用版本:

4 MVCC在读已提交和可重复读下区别

根本原因在于RC隔离级别下事务中每次select都会创建一个read view,而RR隔离级别只会在事务中创建一次read view

4.1 读已提交场景

简单理解:读取已提交最新的数据,能解决脏读,有不可重复度问题。

根本原因:读已提交事务隔离级别下,事务里面每次select查询都会创建一个read view。

举例说明:事务A 进行一次修改,事务B进行两次查询

  1. 首先开启A事务并修改为'北冥-2',事务未提交。(修改前查询最新数据时会生成read view)
  2. 然后开启事务B进行select查询,此时查询到的数据为'北冥',read view 如下
  3. 事务A提交事务。数据被提交到磁盘。
  4. 事务B再次相同select查询,read view如下,此时min_trx_id变成了2,当判断trx_id < min_trx_id满足条件,所以获取到最新数据,和之前数据不一致。因此不可重复度。

4.2 可重复读场景

简单理解:读取已提交最新的数据,能解决脏读,有不可重复度问题。

根本原因:可重复读事务隔离级别下,每个事务只会创建一个read view,同一个事务里面的select操作共用同一个read view。

举例说明:事务A 进行一次修改,事务B进行两次查询

  1. 首先开启A事务并修改为'北冥-2',事务未提交。(修改前查询最新数据时会生成read view)
  2. 然后开启事务B进行select查询,此时生成read view,根据版本链查询到的数据为'北冥'
  1. 即便后面事务A已经提交了事务,最新数据被更改为了'北冥-2',但是事务B的read view 还是之前那个,在根据上面条件进行判断时最新数据中trx_id=2不符合,根据回滚指针找到下一条数据trx_id=1才符合,因此读到的数据跟第一次是一样的。

mysql解决了幻读吗?

只解决了快照读下的幻读,而当前读需要通过间隙锁

RC隔离级别下有间隙锁吗?

没有,

参考

B站 IT老哥 :阿里P7要求这么低吗?老哥给你讲清楚什么是MySQL的MVCC

相关推荐
龙石数据1 小时前
MySQL 全量同步到 Hive 怎么做?三步配置教程
数据库·hive·mysql·数据治理·数据中台
程序员在囧途2 小时前
likeadmin-api API 算力超市怎么做供应商切换?统一鉴权、task_id 和 callback_url 才能稳交付
java·服务器·数据库·开放api·likeadmin-api·api算力超市
数据工匠老o2 小时前
连接池配置实战——从“连不上“到“连太多“的完整排查指南
数据库
一只专注api接口开发的技术猿3 小时前
电商评论自动化监控与情感数据分析完整落地教程(附可直接运行 Python 代码)
大数据·数据库·python·数据分析·自动化
hh真是个慢性子3 小时前
GaussDB Inside 2.23.01.280 集中式一主一备安装
数据库·database·gaussdb·国产数据库·高斯
沉静的小伙3 小时前
Spring事务
java·数据库·spring
大侠锅锅3 小时前
第 3 篇:节点自动化纳管——从裸机到可管理的 7 步安装流水线
数据库·自动化·边缘计算·iot
笃行3503 小时前
踩坑实战 | MySQL/PostgreSQL 迁移必踩:LEFT JOIN 莫名丢数据,KES 外连接消除避坑指南
数据库
摇滚侠3 小时前
Redis7 零基础到进阶 Linux 离线安装 Redis 09-10
数据库·redis·缓存
赵渝强老师4 小时前
【赵渝强老师】达梦数据库的回滚数据
数据库·达梦数据库·国产数据库