MySql —— MVCC版本链

前言

MVCC版本控制是一种Mysql实现隔离级别的机制,其利用版本链以及对应的undo日志,通过快照读取的方法来控制各个级别的事务所能够读取到的信息。

从事务隔离级别问题来说,MVCC能够解决脏读,不可重复读的问题,但是对于幻读则无能为力,所以这里也会顺带总结一下关于数据库幻读的解决方法,便于读者整理完整的思路。

作者本身对于Mysql理解有诸多不足,如果有表述错误或者不当的地方,请及时指出,非常感谢您的阅读。


隔离级别

Mysql提供四隔离级别,分别用来解决四种事务一致性的问题。

那么问题来了,为什么需要需要隔离级别,为什么使用锁技术来让事务串行执行。

答案很简单,效率

MySql是一个服务器,那么就必须支持多个连接。因此Mysql会为每一个连接都去维护一个session,每个客户端在该session中进行数据的读写请求,那么必然会同时出现多个事务操作同一条语句的问题。如何保证数据的一致性最简单的方法就是让多个事务串行执行,但是在高并发下,这会导致大量的事务堆积,成本上是无法接受的。

因此,Mysql的设计者提出了隔离级别的概念,也就是说。

Mysql的隔离级别是通过牺牲一部分隔离性来保证事务的并发执行效率

关于四种隔离级别和解决的问题这里不赘述,网上资料大把大把,主要来说在MVCC下的版本链和readView


版本链

在InnoDB中,一张表必须包含两个字段,trx_idroll_pointer

  • trx_id : 事务字段,当一个事务去操作某个行的数据时,会将自己的事务Id赋值给trx_id字段
  • roll_pointer : 回滚指针,当一个事务更新了一个字段的时候,并不会直接删除掉之前的字段,而是将该指针指向之前的字段存储到undo blog

用一张图来解释一下。

每当事务中更新一条数据时,都会将其添加到undo blog中的,随着更新的次数增多,数据会逐渐被连接成一个链,也就是所说的版本链。


ReadView

实际上,MVCC版本控制主要就是靠版本链与ReadView来维护的。

我们可以将Read View看作一个数组,整个数组的左边界和右边界时当前活跃事务的事务Id。举个例子 :

现在存活事务有事务100,150,200,250

那么Read View就是{100,150,200,250}

//查询事务Id的语句
SELECT tx.trx_id
FROM information_schema.innodb_trx tx
WHERE tx.trx_mysql_thread_id = connection_id()

这个事务Id也就是对应着版本链中的trx_id,那么它的作用是什么呢?

首先我们来看两个最极端的隔离级别,READ UNCOMMITTEDSERIALIZABLE。当隔离级别为读未提交时,Mysql是不做任何隔离性的要求,所以这个时候只需要读取最新的数据即可,这也是脏读产生的原因。同理,串行化的级别是最严苛的事务隔离界别,在这个级别下,是通过加锁的方式对事务进行串行化执行,所以这两个级别是不会使用到版本链以及Read View。

那么剩下的两个级别都使用到了这两个模块,其中有一些细微差异,我们放在之后说,首先来说下是如何进行操作的。

事务执行过程中,只有在第一次真正修改记录时(比如使用INSERT、DELETE、UPDATE语句),才会被分配一个单独的事务id,这个事务id是递增的

上面提到生成的Read View是当前所有活跃事务的事务Id的集合,那么这个集合就有个范围,所以可以通过事务Id来判断这些事务生成时间顺序。下面来看下当一个事务查询一条记录的时候究竟会发生什么。

### MySQL MVCC 实现机制及工作原理 #### 1. MVCC 基本概念 MVCC(Multi-Version Concurrency Control),即多版本并发控制,是一种用于提高数据库系统并发性能的技术。其核心思想是通过维护数据的多个版本,使读写操作能够无冲突地并行执行[^1]。 #### 2. 数据库中的隐藏字段 为了支持 MVCC 的实现,MySQL InnoDB 存储引擎为每一条记录增加了三个重要的隐藏字段: - **DB_TRX_ID**: 记录最后一次对该行修改的事务 ID。 - **DB_ROLL_PTR**: 指向该行之前的某个旧版本,存储在 Undo Log 中。 - **DB_ROW_ID**: 表示物理行的唯一标识符(仅当表未定义主键时使用)。 这些隐藏字段构成了 MVCC 的基础结构,允许系统追踪不同时间点的数据状态[^2]。 #### 3. 快照读与当前读 - **快照读 (Snapshot Read)** 是一种非阻塞的一致性读取方式,适用于大多数 SELECT 查询。它基于 MVCC 提供的历史版本数据构建一致性视图,从而避免了加锁带来的开销。 - **当前读 (Current Read)** 则涉及实际的最新数据,并可能触发锁定行为(如共享锁或排他锁)。这种模式通常应用于 UPDATE 或 DELETE 操作以及某些特定类型的查询语句中。 #### 4. Read View 的作用 Read View 定义了一个事务可见性的逻辑框架,决定了哪些历史版本对于当前事务来说是可以访问的。每次新启动一个只读事务时都会创建一个新的 Read View 。主要包含以下几个关键属性: - m_ids: 当前活跃事务列表; - min_trx_id 和 max_trx_id : 分别表示最小和最大有效事务ID范围; - creator_trx_id: 创建此readview所在事务id; 根据上述规则判断某条记录是否满足条件进而决定返回哪个版本给用户进程调用。 #### 5. Undo Log 工作流程 Undo Logs 保存着每一笔更改之前的状态副本,在发生回滚或者清理过期版本的时候需要用到它们。每当有一项更新动作被执行之后,原初值就会被复制到 undo log 文件里形成新的节点接起来构成所谓的“版本条”。随着后续更多次变更累积下来就形成了完整的演变过程轨迹。 #### 6. 隔离级别的影响 虽然标准SQL规定四种不同的隔离等级——READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 及 SERIALIZABLE ——但是实际上只有最后两种真正依赖于 mvcc 技术来达成预期效果。其中 REPEATABLE READ 下几乎所有的常规检索都属于 snapshot read 类型;而 serializable mode 强制采用 current reads 来确保绝对串行化处理顺序[^3]。 ```sql -- 示例代码展示如何查看undo日志信息(需管理员权限) SHOW ENGINE INNODB STATUS; ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值