前言:
mysql在我们开发当中可谓是非常非常重要呀,特别是在面试当中这可是一个重点,今天我们一起来学习mysql的事务和MVCC。

事务
MySQL 的事务(Transaction)是数据库管理系统中非常重要的一个概念。简单来说,事务是一组原子性的 SQL 查询,要么全部执行成功,要么全部不执行。在 MySQL 中,主要使用 InnoDB 存储引擎来支持事务
事务的四大特性
原子性
事务被视为不可分割的最小单元。要么全部执行成功,要么全部失败回滚。如果执行到一半系统崩溃,数据库会通过 undo log(回滚日志)将数据恢复到事务开始前的状态。
一致性
事务执行前后,数据库的完整性约束没有被破坏。例如:转账业务,A 扣钱 100 元,B 必须增加 100 元,总金额不变。如果原子性、隔离性被破坏,一致性就无法保证。
隔离性
多个事务并发执行时,一个事务的执行不应被其他事务干扰。数据库通过锁机制和 MVCC(多版本并发控制)来实现隔离。
持久性
一旦事务被提交,它对数据库的修改就是永久性的。即使系统随后发生崩溃,通过 redo log(重做日志)也能恢复已提交的数据。
例如,A向B转账500元,这个操作要么都成功,要么都失败,体现了原子性。转账过程中数据要保持一致,A扣除了500元,B必须增加500元。隔离性体现在A向B转账时,不受其他事务干扰。持久性体现在事务提交后,数据要被持久化存储。
并发事务可能引发的问题
脏读:读到其他事务未提交的数据。
不可重复读:同一事务内两次读取同一条记录,数据内容不一致(因为被其他事务修改并提交了)。
幻读:同一事务内两次查询数据,结果第一次查不到,第二次居然查到了(因为其他事务插入了新数据)。
隔离级别
由于并发产生了问题,所以为了解决问题,mysql就有了事务隔离来解决问题。SQL 标准定义了四种隔离级别,MySQL InnoDB 都支持。隔离级别越高,并发性能越低,数据一致性越高。
未提交读(READ UNCOMMITTED):解决不了所有问题。
读已提交(READ COMMITTED):能解决脏读,但不能解决不可重复读和幻读。
可重复读(REPEATABLE READ):能解决脏读和不可重复读,但不能解决幻读,这也是MySQL的默认隔离级别。
串行化(SERIALIZABLE):可以解决所有问题,但性能较低。
在考虑了性能和实际问题最终mysql的默认隔离级别采用了可重复读(REPEATABLE READ)
事务的实现原理
Redo log

Undo log

接下来就是我们的重点MVCC
MVCC
MVCC(多版本并发控制)是 MySQL InnoDB 存储引擎实现高并发、非阻塞读的关键技术。它通过为每行数据保存多个历史版本,让读操作可以读取"快照"数据,而写操作继续更新最新数据,从而避免了传统锁机制下读写互斥的问题,大幅提升并发性能。保证了事务的隔离性。
InnoDB 中 MVCC 的核心实现
在mysql中它的主要实现是
隐藏列
每行记录除了用户定义的列,InnoDB 还会自动添加三个隐藏字段:
-
DB_TRX_ID:最近修改该行的事务 ID。每次对行进行 INSERT、UPDATE、DELETE 时,都会将该事务的 ID 记录在此。
-
DB_ROLL_PTR:回滚指针,指向该行在 Undo Log 中的旧版本记录。通过它可以找到该行的历史版本链。
-
DB_ROW_ID:隐藏主键。如果表没有定义主键,InnoDB 会用这个隐藏列来构造聚簇索引。
Undo Log
Undo Log 中保存了数据被修改前的旧值。当一行数据被修改时,InnoDB 会先将旧值写入 Undo Log,然后更新当前行,并将 DB_ROLL_PTR 指向 Undo Log 中的旧版本记录。
这样,多个事务修改同一行时,就会形成一条版本链 :
当前最新版本→ 旧版本1(通过 DB_ROLL_PTR 指向 Undo 记录)→ 旧版本2 → ......
版本链的头节点就是当前记录,每个节点都包含对应的 DB_TRX_ID(创建该版本的事务 ID)和回滚指针。

Read View
Read View 是 MVCC 中判断哪个版本对当前事务可见的核心数据结构。当事务执行快照读(普通 SELECT)时,会生成一个 Read View,记录当前系统中活跃的事务 ID 列表。
Read View 主要包含以下信息:
-
m_ids:生成 Read View 时,系统中所有活跃(未提交)的事务 ID 列表。
-
min_trx_id:m_ids 中的最小值。
-
max_trx_id:系统下一个要分配的事务 ID(即生成 Read View 时已经分配的最大事务 ID + 1)。
-
creator_trx_id:创建该 Read View 的事务 ID。
说白了快照读就是有啥读啥
最后根据下面这个规则,就可以判断到底访问的是哪个版本的事务

RC隔离级别

在这个隔离级别下,事务中每读一次就会生成一个新的,比如事务五有两个读操作所以就有两个读试图。然后根据比对规则,比如,从当前DB_TRX_ID开始一一比对,4不满足,下一个就是3,谁满足任意一条数据,说明读到了这个版本的事务。
RR隔离级别
只会在第一次读的时候生成然后一直用这个图

总结
这篇文章介绍了mysql的事务和实现原理,以及mvcc及其实现原理,如果这篇文章对你有帮助请给个点赞或者关注支持一下
