MySQL事务&MVCC复习清单
一、数据库事务 ACID 四大特性及底层实现
1. 原子性(Atomic)
核心定义:一个事务内所有 SQL 操作,要么全部执行成功提交,要么全部失败回滚,不存在部分执行的情况。
底层保障:undo log(回滚日志)
实现原理:事务执行数据修改操作时,MySQL 会提前在 undo log 中记录数据修改前的原始快照与反向操作语句。若事务出现异常、回滚、程序崩溃,数据库会读取 undo log 日志,撤销所有已执行的修改,保证事务整体失效。
2. 一致性(Consistent)
核心定义:事务执行前后,数据库的数据约束、业务逻辑、数据完整性保持一致,不会出现非法、残缺数据。
底层保障:原子性、隔离性、持久性 + 数据库自带约束
实现原理:依靠主键约束、唯一索引、外键约束、非空约束等数据库原生规则,结合事务三大特性,杜绝数据错乱、数据不一致问题,是事务的最终目标。
3. 隔离性(Isolation)
核心定义:多个事务并发执行时,各个事务相互独立、互不干扰,避免并发读写产生的数据异常。
底层保障:锁机制 + MVCC 多版本并发控制
实现原理:写操作通过行锁、间隙锁、临键锁实现互斥;读操作通过 MVCC 快照读,实现读写不阻塞,平衡并发安全性与性能。
4. 持久性(Durable)
核心定义:事务一旦提交成功,数据会永久写入数据库,即使服务器宕机、重启,数据也不会丢失。
底层保障:redo log(重做日志)+ binlog(二进制日志)
实现原理:事务提交前优先写入日志落盘,而非直接修改磁盘数据。服务器故障重启后,MySQL 通过 redo log 完成崩溃恢复,落地完整事务数据。
二、四大事务隔离级别(InnoDB 默认 RR)
MySQL InnoDB 提供四种隔离级别,从上到下安全性递增、性能递减,用于解决并发读写异常:
-
读未提交(Read Uncommitted):可读取其他事务未提交数据,存在脏读、不可重复读、幻读,生产环境几乎不用。
-
读已提交(Read Committed,RC):仅能读取其他事务已提交的数据,解决脏读,存在不可重复读、幻读。
-
可重复读(Repeatable Read,RR):MySQL InnoDB 默认隔离级别,解决脏读、不可重复读,通过临键锁规避绝大部分幻读问题。
-
串行化(Serializable):最高隔离级别,事务串行执行,彻底解决所有并发读问题,读写均加锁,性能极差,极少使用。
三、三大并发读异常区分
1. 脏读
场景:一个事务读取到其他事务未提交的修改数据。若对方事务回滚,当前读取的数据属于无效脏数据。
核心特征:读取未提交数据,数据随时失效。
2. 不可重复读
场景:同一个事务内,两次查询单条相同数据,期间其他事务完成数据修改并提交,导致当前事务两次查询结果不一致。
核心特征:聚焦单行数据修改更新。
3. 幻读
场景:同一个事务内,执行范围查询时,其他事务新增或删除数据并提交,导致当前事务多次范围查询,数据条数、查询结果不一致。
核心特征:聚焦范围数据新增、删除。
四、MVCC 核心原理(RR 级别核心)
MVCC(多版本并发控制):适用于 InnoDB 引擎 RC、RR 隔离级别下的快照读,核心作用是实现无锁读、读写互不阻塞,大幅提升数据库并发性能。
1. 数据表隐藏字段
InnoDB 每一条聚簇索引数据,自带三个隐藏字段,是 MVCC 实现的基础:
-
DB_TRX_ID:最后修改当前行数据的事务 ID
-
DB_ROLL_PTR:回滚指针,指向 undo log 中该行数据的历史版本
-
DB_ROW_ID:数据表无主键时,InnoDB 自动生成的默认主键
2. 数据版本链
当事务修改数据时,不会直接覆盖原有数据,而是将修改前的旧数据存入 undo log,通过 DB_ROLL_PTR 指针层层串联。当前最新数据 + 所有历史版本数据,共同组成单向版本链。MVCC 查询数据时,会根据隔离级别规则,遍历版本链筛选当前事务可见的数据版本。
3. ReadView 四大核心字段(核心)
ReadView 是事务查询时生成的读写视图,用于判断数据版本是否可见,包含四个固定字段:
-
m_ids:生成视图时,数据库内所有活跃未提交的事务 ID 集合
-
min_trx_id:m_ids 集合中最小的事务 ID
-
max_trx_id:生成视图时,数据库即将分配的下一个事务 ID(活跃事务最大阈值)
-
creator_trx_id:创建当前 ReadView 的所属事务 ID
4. 数据版本可见性比对规则(核心)
获取数据行的 DB_TRX_ID,与 ReadView 字段依次比对,规则如下:
-
若 trx_id == creator_trx_id:当前事务自身修改的数据,可见
-
若 trx_id < min_trx_id:修改数据的事务已提前提交,可见
-
若 trx_id >= max_trx_id:修改数据的事务尚未启动,不可见
-
若 min_trx_id < trx_id < max_trx_id:trx_id 在 m_ids 活跃集合内则不可见,不在集合内(已提交)则可见
若当前数据版本不可见,通过回滚指针遍历版本链,重复比对规则,直至找到可见版本。
5. RC 与 RR 视图生成区别
-
RC(读已提交):事务内每一次 SELECT 查询,都会生成全新 ReadView,因此无法实现可重复读
-
RR(可重复读):事务内第一次 SELECT 查询生成唯一 ReadView,后续所有查询复用该视图,保证事务内查询结果一致
五、MVCC 经典场景(RR 级别)
场景前提
事务A(RR隔离级别)开启,不执行提交;事务B正常修改数据表数据并提交。
-
事务A第一次查询:生成专属 ReadView,读取当前数据快照,固定查询视图
-
事务B更新数据并提交:生成数据新版本,更新行数据 trx_id,延长数据版本链
-
事务A再次查询:复用第一次生成的 ReadView,不会读取最新数据,遍历版本链读取历史快照数据,两次查询结果完全一致,实现可重复读