Skip to content

Commit 46146f8

Browse files
committed
[fix]数据可见性算法笔误&内容完善
1 parent 1fdb7f1 commit 46146f8

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

Diff for: docs/database/mysql/InnoDB对MVCC的实现.md

+26-4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,24 @@
5656

5757
### ReadView
5858

59+
```c
60+
class ReadView {
61+
/* ... */
62+
private:
63+
trx_id_t m_low_limit_id; /* 大于这个 ID 的事务均不可见 */
64+
65+
trx_id_t m_up_limit_id; /* 小于这个 ID 的事务均可见 */
66+
67+
trx_id_t m_creator_trx_id; /* 创建该 Read View 的事务ID */
68+
69+
trx_id_t m_low_limit_no; /* 事务 Number, 小于该 Number 的 Undo Logs 均可以被 Purge */
70+
71+
ids_t m_ids; /* 创建 Read View 时的活跃事务列表 */
72+
73+
m_closed; /* 标记 Read View 是否 close */
74+
}
75+
```
76+
5977
[`Read View`](https://github.com/facebook/mysql-8.0/blob/8.0/storage/innobase/include/read0types.h#L298) 主要是用来做可见性判断,里面保存了 “当前对本事务不可见的其他活跃事务”
6078

6179
主要有以下字段:
@@ -65,6 +83,10 @@
6583
- `m_ids``Read View` 创建时其他未提交的活跃事务 ID 列表。创建 `Read View`时,将当前未提交事务 ID 记录下来,后续即使它们修改了记录行的值,对于当前事务也是不可见的。`m_ids` 不包括当前事务自己和已提交的事务(正在内存中)
6684
- `m_creator_trx_id`:创建该 `Read View` 的事务 ID
6785

86+
**事务可见性示意图**[图源](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/#MVCC-1)):
87+
88+
![trans_visible](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/trans_visible.jpg)
89+
6890
### undo-log
6991

7092
`undo log` 主要有两个作用:
@@ -90,23 +112,23 @@
90112

91113
![](https://ddmcc-1255635056.file.myqcloud.com/6a276e7a-b0da-4c7b-bdf7-c0c7b7b3b31c.png)
92114

93-
不同事务或者相同事务的对同一记录行的修改,会使该记录行的 `undo log` 成为一条链表,链首就是最新的记录,链尾就是最早的旧记录
115+
不同事务或者相同事务的对同一记录行的修改,会使该记录行的 `undo log` 成为一条链表,链首就是最新的记录,链尾就是最早的旧记录
94116

95117
### 数据可见性算法
96118

97119
`InnoDB` 存储引擎中,创建一个新事务后,执行每个 `select` 语句前,都会创建一个快照(Read View),**快照中保存了当前数据库系统中正处于活跃(没有 commit)的事务的 ID 号**。其实简单的说保存的是系统中当前不应该被本事务看到的其他事务 ID 列表(即 m_ids)。当用户在这个事务中要读取某个记录行的时候,`InnoDB` 会将该记录行的 `DB_TRX_ID``Read View` 中的一些变量及当前事务 ID 进行比较,判断是否满足可见性条件
98120

99121
[具体的比较算法](https://github.com/facebook/mysql-8.0/blob/8.0/storage/innobase/include/read0types.h#L161)如下:[图源](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/#MVCC-1)
100122

101-
![markdown](https://ddmcc-1255635056.file.myqcloud.com/8778836b-34a8-480b-b8c7-654fe207a8c2.png)
123+
![](https://ddmcc-1255635056.file.myqcloud.com/8778836b-34a8-480b-b8c7-654fe207a8c2.png)
102124

103125
1. 如果记录 DB_TRX_ID < m_up_limit_id,那么表明最新修改该行的事务(DB_TRX_ID)在当前事务创建快照之前就提交了,所以该记录行的值对当前事务是可见的
104126

105127
2. 如果 DB_TRX_ID >= m_low_limit_id,那么表明最新修改该行的事务(DB_TRX_ID)在当前事务创建快照之后才修改该行,所以该记录行的值对当前事务不可见。跳到步骤 5
106128

107129
3. m_ids 为空,则表明在当前事务创建快照之前,修改该行的事务就已经提交了,所以该记录行的值对当前事务是可见的
108130

109-
4. 如果 m_up_limit_id <= DB_TRX_ID < m_up_limit_id,表明最新修改该行的事务(DB_TRX_ID)在当前事务创建快照的时候可能处于“活动状态”或者“已提交状态”;所以就要对活跃事务列表 m_ids 进行查找(源码中是用的二分查找,因为是有序的)
131+
4. 如果 m_low_limit_id <= DB_TRX_ID < m_up_limit_id,表明最新修改该行的事务(DB_TRX_ID)在当前事务创建快照的时候可能处于“活动状态”或者“已提交状态”;所以就要对活跃事务列表 m_ids 进行查找(源码中是用的二分查找,因为是有序的)
110132

111133
- 如果在活跃事务列表 m_ids 中能找到 DB_TRX_ID,表明:① 在当前事务创建快照前,该记录行的值被事务 ID 为 DB_TRX_ID 的事务修改了,但没有提交;或者 ② 在当前事务创建快照后,该记录行的值被事务 ID 为 DB_TRX_ID 的事务修改了。这些情况下,这个记录行的值对当前事务都是不可见的。跳到步骤 5
112134

@@ -210,6 +232,6 @@
210232
## 参考
211233

212234
- **《MySQL 技术内幕 InnoDB 存储引擎第 2 版》**
213-
214235
- [Innodb 中的事务隔离级别和锁的关系](https://tech.meituan.com/2014/08/20/innodb-lock.html)
215236
- [MySQL 事务与 MVCC 如何实现的隔离级别](https://blog.csdn.net/qq_35190492/article/details/109044141)
237+
- [InnoDB 事务分析-MVCC](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/)

0 commit comments

Comments
 (0)