笔记来源:https://www.bilibili.com/video/BV1E44y1B77X?p=1
MVCC
多版本并发控制,提高读写效率
MVCC的实现,通过保存数据在某个时间点的快照来实现的。这意味着一个事务无论运行多长时间,在同一个事务里能够看到数据一致的视图。根据事务开始的时间不同,同时也意味着在同一个时刻不同事务看到的相同表里的数据可能是不同的。
基础知识
当前读
读取的是数据的最新版本,总是读取到最新的数据。
触发时机:
select ... lock in share mode
select ... for update
update ...
delete ...
insert ...
快照读
读取的是历史版本的数据。
触发时机:
select ...
MVCC
案例演示

MVCC包含三部分:
第一部分:隐藏字段
每一行记录上都会包含几个用户不可见的字段。
- DB_TRX_ID 创建或者最后一次修改该记录的事务 id
- DB_ROW_ID 隐藏主键 【索引列的选择过程 主键 ---> 唯一键 ---> 六字节的ROW_ID】
- DB_ROLL_ID 回滚指针 【指向上一个对应的历史记录】配合 undolog 使用
插入一条记录的数据状态:

第二部分:undolog 【回滚日志】
undolog 案例
- 事务1,插入一条新纪录

-
事务2,修改插入的记录,undolog 存储的是历史记录
注意 当前记录 DB_TRX_ID变为当前事务 id
DB_ROLL_PRT 指向上一个版本记录

-
事务3,修改记录
存在多个历史版本

小结:
当不同的事务对同一条记录做修改的时候,会导致该记录的undolog 形成一个线性表,也就是链表,链表首是最新的历史记录,而链尾是最早的历史记录。
第三部分:readview 【事务在进行快照读的时候产生的读视图】
readview 包含以下几部分:
- trx_list 当前系统活跃的事务id
- up_limit_id 列表中事务最小id
- low_limit_id 系统尚未分配的下一个事务id
实际场景1:
事务1 | 事务2 | 事务3 | 事务4 |
---|---|---|---|
开启事务 | 开启事务 | 开启事务 | 开启事务 |
修改某一个值<br />commit | |||
快照读 |
事务2能否读取到刚刚修改的记录值?
可以读取到

可见性判断

RC、RR readview 生成时机

实际场景2:
事务0 | 事务1 | 事务2 | 事务3 | 事务4 |
---|---|---|---|---|
开启事务<br />插入<br />提交 | 开启事务 | 开启事务<br />快照读 | 开启事务 | 开启事务 |
修改某一个值<br />commit | ||||
快照读 |
事务2能否读取到刚刚修改的记录值?
不可以读取到

可见性判断1:
当事务2,进行第一次快照读时【能够读取到事务0,插入的数据】

可见性判断2:
当事务4,进行修改提交之后,事务2再次进行快照读,在 RR 隔离级别下,不会重新生成readview,使用的还是之前的readview

RR 始终读的是第一次快照读吗?
第五步执行的是当前读【快照重新生成,产生了幻读的问题】,所以更新数据为4条。第五步之后再次查询,查询的也是四条记录。

MySQL事务的四大特性:
原子性:通过undolog 实现。
隔离性:通过MVCC 实现。
持久性:通过redolog 实现。涉及到二阶段体提交
一致性:是数据库的根本要求,其他三个特性共同实现了一致性。

二阶段提交

数据更新流程:

如果两个日志只有一个写成功了,会出现什么问题?

网友评论