MySQL-事务(下)-MySQL事务隔离级别与MVCC

目录

一、事务隔离级别

(一)不同隔离级别与问题的关系

(二)MySQL默认隔离级别

二、MVCC:多版本并发控制的奥秘

(一)MVCC的前提知识

[1. 3个记录隐藏字段](#1. 3个记录隐藏字段)

[2. undo日志](#2. undo日志)

[3. Read View](#3. Read View)

(二)MVCC的工作流程

[(三)Read View与可见性判断](#(三)Read View与可见性判断)

三、RR与RC的本质区别

四、总结


在数据库的世界里,事务是保证数据一致性的核心机制,而事务隔离级别和多版本并发控制(MVCC)则是事务处理中极为关键的技术点。今天,我们就来深入探究MySQL中的事务隔离级别以及MVCC的工作原理。

一、事务隔离级别

事务隔离级别定义了多个事务并发执行时,一个事务能看到其他事务操作的程度。MySQL有四种隔离级别,从低到高分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和可串行化(Serializable)。

(一)不同隔离级别与问题的关系

隔离级别 脏读 不可重复读 幻读 加锁读

**- 脏读:一个事务读取到另一个事务未提交的修改数据。

  • 不可重复读:一个事务内多次读取同一数据,结果因其他事务修改而不同(重点是修改和删除操作导致)。
  • 幻读:一个事务内多次查询,结果集因其他事务新增记录而不同(重点是新增记录导致)** 。

(二)MySQL默认隔离级别

MySQL默认的隔离级别是可重复读(Repeatable Read)。这是一个比较均衡的选择,它能避免脏读、不可重复读和幻读问题,同时相比可串行化隔离级别,并发性能更好。一般情况下,不建议修改这个默认设置,因为它在大多数场景下能很好地平衡数据安全性和数据库并发性能。

二、MVCC:多版本并发控制的奥秘

多版本并发控制(MVCC)是MySQL在可重复读等隔离级别下,**实现高效并发读操作的关键技术。**它通过维护数据的多个版本,使得读操作不需要加锁(或减少锁的使用),从而提高数据库的并发性能。

(一)MVCC的前提知识

要理解MVCC,需要先了解以下三个关键概念:

1. 3个记录隐藏字段

  • DB_TRX_ID:6字节,记录最近修改(修改/插入)该记录的事务ID。

  • DB_ROLL_PTR:7字节,回滚指针,指向该记录的上一个版本(这些版本数据一般存储在undo log中)。

  • DB_ROW_ID:6字节,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。

此外,还有一个删除flag隐藏字段,记录被更新或删除时,并非真正删除,而是删除flag发生变化。

2. undo日志

undo log可以简单理解为MySQL中的一段内存缓冲区,用来保存旧数据。当事务需要回滚或者MVCC需要获取历史版本数据时,就会用到undo log中的内容。

3. Read View

Read View是事务进行快照读操作时产生的读视图。在事务执行快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(每个事务开启时,都会被分配一个递增的ID)。Read View本质是用来进行可见性判断的,即判断当前事务能够看到哪个版本的数据(可能是当前最新数据,也可能是undo log里的某个历史版本数据)。

(二)MVCC的工作流程

以一个简单的例子来模拟MVCC的工作过程:

假设我们有一个 student 表,结构如下:

sql 复制代码
CREATE TABLE IF NOT EXISTS student(
    name VARCHAR(11) NOT NULL,
    age INT NOT NULL
);

插入一条记录:

sql 复制代码
INSERT INTO student (name, age) VALUES ('张三', 28);

此时,该记录的隐藏字段情况大致为:DB_TRX_ID 为 null (表示创建该记录的事务ID,这里假设为初始状态), DB_ROW_ID 为 1 , DB_ROLL_PTR 为 null (因为没有历史版本)。

步骤 事务 10 操作流程 事务 11 操作流程
1 开始执行,准备修改 student 表中 name 为 "张三" 的记录 -
2 给目标记录加锁 -
3 将该记录拷贝到 undo log 中(写时拷贝) -
4 修改原始记录的 name 为 "李四" -
5 修改原始记录隐藏字段 DB_TRX_ID 为事务 10 的 ID -
6 修改原始记录回滚指针 DB_ROLL_PTR,指向 undo log 中副本数据的地址 -
7 事务 10 提交,释放锁 -
8 - 开始执行,准备修改 student 表中 name 为 "李四" 的记录
9 - 给目标记录加锁
10 - 将该记录(当前为 "李四" 的记录)拷贝到 undo log
11 - 修改原始记录的 age 为 38
12 - 修改原始记录隐藏字段 DB_TRX_ID 为事务 11 的 ID
13 - 修改原始记录回滚指针 DB_ROLL_PTR,指向 undo log 中刚拷贝的副本数据地址
14 - 事务 11 提交,释放锁

现在,我们就有了一个基于链表记录的历史版本链,所谓的回滚,就是用历史数据覆盖当前数据。

(三)Read View与可见性判断

当事务进行快照读时,会生成Read View,然后根据Read View中的信息(如当前活跃事务ID集合、高水位、低水位等)来判断数据版本的可见性。

例如:

Read View中有 m_ids (Read View生成时刻系统正活跃的事务ID列表)、

up_limit_id ( m_ids 列表中事务ID最小的值)、

low_limit_id (Read View生成时刻系统尚未分配的下一个事务ID,即目前已出现过的事务ID的最大值+1)、

creator_trx_id (创建该Read View的事务ID)等信息。

在实际读取数据版本链时,会获取到每个版本对应的事务ID(即记录的 DB_TRX_ID ),然后根据Read View中的这些信息来判断该版本是否对当前事务可见。如果当前版本不可见,就通过回滚指针遍历下一个版本,直到找到可见的版本或者遍历完版本链。

三、RR与RC的本质区别

可重复读(RR)和读已提交(RC)隔离级别最本质的区别在于Read View生成时机的不同:

**- 在RC隔离级别下,事务中每次快照读都会生成并获取最新的Read View。这就导致在RC级别下,事务内的多次快照读可能会看到不同的结果,因此RC级别存在不可重复读问题。

  • 在RR隔离级别下,同一个事务中的第一次快照读会创建一个Read View,之后该事务后续的快照读都使用同一个Read View。所以,只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,对之后的修改不可见,从而避免了不可重复读问题。**

四、总结

事务隔离级别和MVCC是MySQL事务处理中非常重要的内容。事务隔离级别决定了事务间的隔离程度,平衡了数据安全性和并发性能;而MVCC则是在特定隔离级别下,实现高效并发读操作的核心技术。理解它们的工作原理,对于我们设计和优化数据库应用,以及排查数据库并发问题都有着至关重要的作用。

相关推荐
流火无心1 小时前
mysql索引优化实战
mysql·优化·索引
C++chaofan1 小时前
Spring Task快速上手
java·jvm·数据库·spring boot·后端·spring·mybatis
geovindu4 小时前
sql: Creating a Delimited List from Table Rows
mysql·postgresql·oracle·sqlserver
三贝5 小时前
Java面试现场:Spring Boot+Redis+MySQL在电商场景下的技术深度剖析
spring boot·redis·mysql·微服务·分布式事务·java面试·电商系统
RestCloud5 小时前
从 Oracle 到 TiDB,通过ETL工具,高效实现数据拉通
数据库·oracle
阿里云大数据AI技术5 小时前
[VLDB 2025]阿里云大数据AI平台多篇论文被收录
数据库·flink
ningqw5 小时前
MySQL-事务
mysql
Direction_Wind6 小时前
flinksql bug: Non-query expression encountered in illegal context
数据库·sql·bug
程序边界6 小时前
传统数据库out啦!KINGBASE ES V9R1C10 开启国产数据库“修仙”新纪元!
数据库
DemonAvenger7 小时前
MySQL视图与存储过程:简化查询与提高复用性的利器
数据库·mysql·性能优化