什么是MVCC
多版本并发控制:读取数据时通过一种类似快照的方式将数据保存下来。
MVCC只在READ COMMITTED和REPEATABLE READ两个隔离级别下工作。其他两个隔离级别够和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。
MVCC执行整体流程:
先用表格表示一下程序执行的流程;从上往下每个表格表示每一时刻;
Transaction100 | Transaction200 | Transaction300 | Transaction400 | select 1 mysql(可重复读) | |||||||||||||||
update test set n='1' where id = 1; | |||||||||||||||||||
update test set n='2' where id = 2; | |||||||||||||||||||
update test set n='3' where id = 3; | |||||||||||||||||||
update test set n='4' where id = 4; | |||||||||||||||||||
update dog set n='旺财' where id = 2; | |||||||||||||||||||
commit; | |||||||||||||||||||
update dog set n='小黑' where id = 2; | |||||||||||||||||||
update dog set n='小白' where id = 2; | |||||||||||||||||||
update dog set n='来福' where id = 2; | |||||||||||||||||||
commit; | |||||||||||||||||||
update dog set n='小灰' where id = 2; | |||||||||||||||||||
select n from dog where id = 2; |
简单解释一下,详细内容介绍请看最后面;
存在两个数据库表,test和dog表,test仅仅为了生存事务ID而创建的,dog表一个存在两个属性一个为name一个为ID(设置为了主键)
1、update test set n='1' where id = 1; 这个sql语句是为了产生事务ID,没有其他意义,因为只有事务对数据库修改或者添加是会产生事务ID
2、当执行 select n from dog where id = 2;时会生成快照(Read View)这里是 可以形容为数组【100,300】200,400,这个数组可以知道已经提交的事务ID和未提交的事务ID,所以100和300放在一起了
根据快照 去undo log日志中去读取事务ID(版本链)就可以知道select读取的内容是什么,这里读取的是dog的name为“来福”:也就在快照中(从最新一端开始读取,从上往下)读取到第一个已提交事务ID(快照中存在已提交事务ID),然后结束查找。
流程图如下:红色表示已提交,蓝色表示未提交
需要注意:
当读取事务ID小于快照中最小值时,那么这个事务ID对应的事务一定是已提交的,可见
当读取事务ID大于快照中最大值是,那么这个事务ID对应的事务应该是未提交的,不可见(因为可重复读,读取的时间不一定是最新的,以快照图为准)
当读取事务ID在快照中时,如果事务ID等于自己,那么可见
当读取事务ID在快照中时,如果事务ID已提交,那么可见
再看一下这里 我们添加 update dog set n='球球' where id = 2; 并commit; 重新查询得到的结果仍然是 来福
原因:mysql可重复读,读取的快照不变,它并不知道一已经提交了事务ID100
Transaction100 | Transaction200 | Transaction300 | Transaction400 | select 1 mysql(可重复读) | |||||||||||||||
update test set n='1' where id = 1 | |||||||||||||||||||
update test set n='2' where id = 2 | |||||||||||||||||||
update test set n='3' where id = 3 | |||||||||||||||||||
update test set n='4' where id = 4 | |||||||||||||||||||
update dog set n='旺财' where id = 2; | |||||||||||||||||||
commit; | |||||||||||||||||||
update dog set n='小黑' where id = 2; | |||||||||||||||||||
update dog set n='小白' where id = 2; | |||||||||||||||||||
update dog set n='来福' where id = 2; | |||||||||||||||||||
commit; | |||||||||||||||||||
update dog set n='小灰' where id = 2; | |||||||||||||||||||
select n from dog where id = 2 | |||||||||||||||||||
update dog set n='球球' where id = 2; | |||||||||||||||||||
commit; | |||||||||||||||||||
select n from dog where id = 2 |
流程图如下:红色表示已提交,蓝色表示未提交