【数据库知识】MVCC机制——MySql底层原理版【详细版】
MVCC机制——MySql底层原理版
undo回滚日志+记录版本链(增加了两个字段:事务id和回滚指针(指向历史记录))
readview:活跃事务id组+最大事务id
匹配原则:分段:已提交、已提交/未提交、未提交
由版本链从上到下进行匹配
(1)当前事务id<min_id,则表示当前记录在第一段,表示已提交,直接读出;
(2)min_id<=当前事务id<=max_id,则表示当前记录在第二段,表示可能提交,也可能未提交,那么根据readviw,看当前事务id是否在活跃事务id组,若在则表示未提交,继续向下进行匹配,若不在,表示已提交,那么直接读出; (3)当前事务id>max_id,则表示当前记录在第三段,表示未提交,那么继续向下匹配。
#事务id=100 | #事务id=200 | #事务id=300 | #select1 | #select2 |
begin; | begin; | begin; | begin; | begin; |
update test set name='hm' where id=1; | ||||
update test set name='hm' where id=2; | ||||
update test set name='yyqx' where id=1; | ||||
commit; | ||||
select name from test where id=1; --readview[100,200],300 yyqx | ||||
update test set name='hm1' where id=1; | ||||
update test set name='hm2' where id=1; | ||||
select name from test where id=1; --readview[100,200],300 yyqx | ||||
commit; | update test set name='hm3' where id=1; | |||
update test set name='hm4' where id=1; | ||||
select name from test where id=1; --readview[100,200],300 yyqx | select name from test where id=1; --readview[200],300 hm2 | |||
commit; |
以上是一个事务例子,一共有三个事务,事务id分别为100、200、300,表格从上到下是时间顺序,当执行第一条select语句时,也就是#select1中的select name from test where id=1; 此时版本链是如下这样的:
匹配原则:由版本链从上到下开始匹配,第一个记录的事务id为300,在未提交/已提交段,那么根据readview,发现不在活跃事务id组,那么表示此记录已提交,直接读出,所以结果就是:yyqx
当执行第二条select语句,也就是#select中的select name from test where id=1;此时版本链如下所示:
匹配原则:由版本链从上到下开始匹配,第一个记录的事务id为100,在未提交/已提交段,那么根据readview,发现在活跃事务id组,那么表示此记录未提交,继续向下匹配,同样的,第二条记录的事务id还是100,也同样未提交,所以继续向下匹配,第三条记录的事务id是300,在未提交/已提交段,那么根据readview,发现不在活跃id组,那么表示此记录已提交,直接读出,所以结果就是:yyqx
当执行第三条select语句时,也就是#select1中的select name from test where id=1;此时版本链如下所示:
匹配原则:由版本链从上到下开始匹配,第一个记录的事务id为200,在未提交/已提交段,那么根据readview,发现在活跃事务id组,那么表示此记录未提交,继续向下匹配,同样的,第二条记录的事务id还是200,也同样未提交,所以继续向下匹配,同样的,第三条记录的事务id还是100,也同样未提交,所以继续向下匹配,同样的,第四条记录的事务id还是100,也同样未提交,所以继续向下匹配,第五条记录的事务id是300,在未提交/已提交段,那么根据readview,发现不在活跃id组,那么表示此记录已提交,直接读出,所以结果就是:yyqx
注:同一个事务的readview是延续第一条select语句的readview,所以查询结果还是yyqx——可重复读
若是读已提交,那么readview会进行更新,这里介绍的是可重复读情况
当执行第四条select语句,也就是#select2中的select name from test where id=1;,此时版本链如下所示:
匹配原则: 由版本链从上到下开始匹配,第一个记录的事务id为200,在未提交/已提交段,那么根据readview,发现在活跃事务id组,那么表示此记录未提交,继续向下匹配,同样的,第二条记录的事务id还是200,也同样未提交,所以继续向下匹配,第三条记录的事务id是100,在已提交段,所以直接读出,结果为hm2
注:当前重新开始了一个事务,所以重新分配readview