文章目录
MVCC 基本概念
当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select…lock in share mode(共享锁),select…for update、update、insert、delete(排他锁)都是一种当前读。
快照读
简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
Read Committed:每次select,都生成一个快照读。
RepeatableRead:开启事务后第一个select语句才是快照读的地方。
Serializable:快照读会退化为当前读。
演示当前读和快照读的区别:
MVCC
全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为 MySQL 实现 MVCC 提供了一个非阻塞读功能、一种无锁的实现方式。
MVCC 的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。
MVCC 实现原理
隐藏字段
MySQL 中的行数据,除了我们肉眼能看到的字段之外,其实还包含了一些隐藏字段,它们在内部使用,默认情况下不会显示给用户。如下图除了 id、age、name 用户创建的字段,还有 DB_TRX_ID、DB_ROLL_PTR
字段 | 含义 |
---|---|
DB_TRX_ID | 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。 |
DB_ROLL_PTR | 回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。 |
DB_ROW_ID | 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。 |
undo log 日志
undo 日志(Undo Log)是 MySQL 中的一种重要的事务日志,undo 日志的作用主要有两个方面:
- 事务回滚:记录数据在执行之前是什么样子的,在 insert、update、delete 的时候产生的便于数据回滚的日志。
- MVCC 实现:MVCC 是 InnoDB 存储引擎的核心特性之一。通过使用 undo 日志,MySQL 可以为每个事务提供独立的事务视图,使得事务读取数据时能看到一致且符合隔离级别要求的数据版本。
undo log 的版本链
不同事务或相同事务对同一条记录进行修改,会导致该记录的 undo log 生成一条记录版本链表,链表的头部是最新的旧记录,链表的尾部是最早的旧记录,回滚指针指向最近的一次的修改记录。
如下图:
事务 2 将 age 改为 3,修改该行数据时,数据库会先对该行加排他锁,然后把该行数据拷贝到 undo log 中作为旧记录,即在 undo log 中有当前行的拷贝副本,当拷贝完成后,隐藏字段中的 BD_TRX_ID 会自增,DB_ROLL_PTR 回滚指针指向 undo log 的副本记录,即表示我的上一个版本就是它,事务提交后,释放锁。
事务 3、4 同理,指向上一个版本,此时就形成了一条版本链。
具体流程如下:
- 在更新或删除操作之前,MySQL 会将旧值写入 undo log 中。
- 当事务需要回滚时,MySQL 会根据事务的 undo log 记录,通过 DB_ROLL_PTR 找到对应的 undo log。
- 根据 undo log 中记录的旧值,MySQL 将旧值恢复到相应的数据行中,实现数据的回滚操作。
ReadView
ReadView(读视图)是快照读 SQL 执行时 MVCC 提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。
ReadView 中包含了四个核心字段:
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合(或者叫未提交的事务ID) |
min_trx_id | 最小活跃事务ID(在m_ids找个最小的) |
max_trx_id | 预分配事务ID,就是当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | ReadView 创建者的事务ID |
其中版本链数据访问规则为:
不同的隔离级别,生成 ReadView 的时机不同:
READ COMMITTED:在事务中每一次执行快照读时生成ReadVieW。
REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该 ReadView,所以才叫可以重复读。
RC 隔离级别下的 MVCC
以第一次查询为例:
trx_id(当前事务ID):4 -> 3 -> 2 -> 1
m_ids(当前活跃的事务ID集合):{3,4,5}
min_trx_id(最小活跃事务ID):3
max_trx_id(预分配事务ID,当前最大事务ID+1):6
creator_trx_id(ReadView创建者的事务ID):5
从条件一至到条件四,trx_id一直从 4 -> 3 -> 2 -> 1,只要有规则成立的就返回当条记录
在图上例子中,当 trx_id 等于 2 的时候,trx_id < min_trx_id 成立了,所以就返回该条记录
RR 隔离级别下的 MVCC
在 RC 隔离级别,同一个事务中读取两次相同的记录是一样的,因为在第一次读取数据时生成一个 ReadView,后面会复用第一次生成的,所以才叫可重复读。
标签:事务,log,记录,MVCC,undo,详解,MySQL,ID From: https://blog.csdn.net/m0_72918997/article/details/142341677