MySQL MVCC原理
1. Read View 概念
在InnoDB中,可重复读(RR)/快照读(MVCC快照),会创建一个"Read View",它是判断查询时哪些行在当前事务(A)可见的关键结构。
2. Read View 的关键字段
在**源码(比如trx0rseg/trx0trx/trx0read.c)**中,常见的数据结构有这几个关键字段:
- up_limit_id(upper limit trx id)
"最大不可见事务id"。所有id小于这个值的事务都是已提交的/data可见。 - low_limit_id(lower limit trx id)
"最小未提交事务id"。所有id大于等于这个值的事务,肯定是开启在当前快照之后,不可见。
在具体源码(比如read_view_t
结构体中):
typedef struct read_view_struct read_view_t;
struct read_view_struct {trx_id_t low_limit_id;trx_id_t up_limit_id;trx_ids_t* trx_ids;/* ... 其他字段 ... */
}
4. 代码实现层面
在 InnoDB 的源码里,是否可见的关键判断如下(以伪代码表达就是这个逻辑):
if (row_trx_id < read_view->up_limit_id) {// 行的版本是已提交,快照可见return true;
}
if (row_trx_id >= read_view->low_limit_id) {// 行版本是未提交的,快照不可见return false;
}
if (is_in_trx_ids(row_trx_id, read_view->trx_ids)) {// 行版本属于活跃事务,还没提交,不可见return false;
} else {// 行版本已经提交,可见return true;
}
5. 小结
- up_limit_id:在ReadView生成那一刻,数据库系统里已提交的最大事务id;小于它的行都已提交。
- low_limit_id:ReadView生成时活跃事务里的最大事务id+1;大于等于它的都是新事务,肯定不可见。
- trx_ids:是ReadView生成时所有活跃事务id的集合。用于判断“中间区间”事务是否已提交。
行的可见性用这三者一起判定。
假设当前活跃事务ID列表:
活跃事务ID(未提交):[11, 13, 14]
up_limit_id = 11
low_limit_id = 15
那可见性判断:
trx_id < 11 ——已commit,肯定可见
trx_id >= 15 ——快照之后事务创建,不可见
trx_id = 12 ——12 号事务已 commit 并离开活跃列表(不在 [11,13,14]),可见
trx_id = 13 ——还在活跃列表,未 commit,不可见