Mysql——MVCC学习

概念:

MVCC,即多版本并发控制,是InnoDB实现高并发事务的核心机制。它的核心思想是:不通过加锁阻塞读写,而是为每一行数据维护多个历史版本,让读写事务可以无冲突地并发进行。这是InnoDB在"可重复读"和"读已提交"隔离级别下实现的关键。

解决问题

  • 解决脏读:因为事务只能看到已提交事务产生的版本。

  • 解决不可重复读(在"可重复读"级别下):因为在一个事务内第一次快照读就创建 了ReadView,之后的所有快照读都复用这个ReadView,所以看到的数据 snapshot 是一致的。

当前数据行的关键数据结构

  • DB_TRX_ID(6字节):事务ID。记录最后一次插入或更新这行数据的事务ID。

  • DB_ROLL_PTR(7字节):回滚指针。指向这行数据上一个版本的undo log记录地址,是构成版本链的关键。

  • DB_ROW_ID(6字节):行ID。如果表没有主键,InnoDB会用它生成聚簇索引。

Undo log

  • 每次修改数据时(INSERT/UPDATE/DELETE),都会在undo log中记录一条逻辑相反的日志,用于回滚和构建历史版本。

  • UPDATE操作会产生一个"更新日志",其中包含了被修改前的数据镜像,并通过DB_ROLL_PTR串联起来,形成一条单向链表,即"版本链"。链头是最新数据,链尾是最老数据。

链表节点存储数据

python 复制代码
class UndoLogNode():
	def __init__(tri_id, preNode, data):
		self.data = data # 该行数据被修改前的完整内容
		self.tri_id = tri_id # 该记录产生时对应的事务ID
		self.pre_node = preNode or None # 指向更早一个版本的Undo Log记录的指针

ReadView

在事务执行第一个快照读时,根据瞬间截取的当时数据库系统的一个全局状态快照创建,它定义了当前事务能看到哪些版本的数据。

数据结构

  • m_ids:生成ReadView时,系统中活跃的(未提交的)读写事务ID列表。这个列表是从全局事务表中实时获取的。

  • min_trx_id:m_ids中的最小值。由 m_ids列表直接计算得出

  • max_trx_id:生成ReadView时,系统应该分配给下一个事务的ID。通常是当前的全局事务 ID (trx_sys->max_trx_id) + 1。

  • creator_trx_id:创建该ReadView的事务自己的ID。

工作流程

查询时

  1. 定位数据行:首先找到数据页中最新的那条记录。

  2. 遍历版本链:顺着该记录的DB_ROLL_PTR指针,在undo log中遍历它的历史版本链表。

  3. 可见性判断(核心规则):

    • 拿每个版本中的DB_TRX_ID(即产生该版本的事务ID),与当前ReadView进行比对:

    • 如果 DB_TRX_ID< min_trx_id,说明这个版本是在当前事务开始前就已提交的,可见。

    • 如果 DB_TRX_ID>= max_trx_id,说明这个版本是在当前事务开始后才开启的,不可见,继续找更老的版本。

    • 如果 min_trx_id<= DB_TRX_ID< max_trx_id,则需要判断DB_TRX_ID是否在m_ids(活跃事务列表)中:

      • 如果在,说明生成该版本的事务在ReadView创建时还未提交,不可见。

      • 如果不在,说明生成该版本的事务在ReadView创建时已提交,可见。

  4. 返回数据:找到第一个对当前事务可见的版本,将其数据返回。如果遍历完链都没找到,则说明此行对当前事务不可见。

MVCC工作流程

  1. 准备工作(由 InnoDB 自动维护)
    • Undo Log 记录历史
    • 构建版本链:表中的当前数据行,其隐藏字段 DB_ROLL_PTR指向了最近一次修改它所产生的 Undo Log 记录。
  2. 创建裁判规则ReadView
  3. ReadView执行其工作流程
相关推荐
2401_871696522 小时前
CSS如何优化移动端CSS选择器性能_遵循BEM规范避免过长嵌套
jvm·数据库·python
jiayong232 小时前
第 33 课:任务看板视图(按状态分列)与本地持久化
开发语言·前端·javascript·学习
是宇写的啊2 小时前
MyBatis-2
数据库
2401_883600252 小时前
Cgo 回调中处理 const char- 参数的正确方法
jvm·数据库·python
m0_737539372 小时前
redis的安装
数据库·redis·缓存
zqit rdlo2 小时前
MYSQL 创建索引
数据库·mysql
gmaajt2 小时前
CSS 背景图片无法加载的常见原因与正确写法详解
jvm·数据库·python
2601_949816682 小时前
MySQL 数据库连接池爆满问题排查与解决
android·数据库·mysql
解救女汉子2 小时前
Python如何计算NumPy数组的协方差矩阵_调用cov函数进行特征分析
jvm·数据库·python