miaosha/docs/mysql-mvcc.md

4.1 KiB
Raw Permalink Blame History

MVCC原理

Multi-Version Concurrency Control,翻译为中文即多版本并发控制使用它来实现RR以及RC隔离级别下读取数据的隔离性。串行话可以理解为直接用锁而读未提交可以理解成什么也不控制。

innodb为每一行记录都实现了三个隐藏字段
DB_ROW_ID 6个字节: 行标识
DB_TRX_ID   6个字节删除、插入或者更新行的最后一个事物id自动增长
DB_ROLL_PTR 7个字节回滚指针
#transaction 100 #transaction 200 #transaction 300 #select 1 #select 2
bengin bengin bengin
update test set cl = '123' where id =1;
update test set cl = '123' where id =1;
update account set name = 'lilei300' where id =1;
commit;
select name from account where id=1; readview[100,200] 300 --> lilei300
update account set name = 'lilei1' where id =1;
update account set name = 'lilei2' where id =1;
select name from account where id=1; readview[100,200] 300 --> lilei300
commit; update account set name = 'lilei3' where id =1;
update account set name = 'lilei4' where id =1;
select name from account where id=1; readview[100,200] 300 --> lilei300 select name from account where id=1; readview[200] 300 --> lilei2
commit;

版本变更流程

操作的时候会生成事务id
①每条记录都会拼接trx_id事务id和roll_pointer(回滚指针)2个字段
②每次操作会将就数据移动到undo log修改后数据的回滚指针指向undo log中这条数据

查询的时候会读取出ReadView一致性视图【未提交的事务id】数组+已创建的最大事务id
可重复读会在事物中第一次读数据时生成readview
读已提交会在事务中每次读取数据时生成readview

匹配规则:
1.当表中数据事务id < readview未提交事务最小值数据可见
2.当表中数据事务id > readview最大事务id说明本次事务开启时表中数据事务都还没开启。 数据不可见
3.当表中数据事务id in readview未提交数组里说明这个事务还未提交不可见。 特殊的:如果事务是当前事务,依旧可见
4.当表中数据事务id > readview未提交数组里 || 当表中数据事务id < readview已创建的最大事务id 可见

删除算修改的一种特殊情况会在undo log 的record header中记录下delete flag如果被删除了就忽略这条数据。

匹配规则

MVCC & 2PL解决了部分幻读问题

主要参考https://www.zhihu.com/question/372905832分别讲了MVCC和2PL悲观锁对应还有OCC乐观锁解决的幻读问题
ps幻读主要在insert不可重复读主要在delete & update

MVCC解决的幻读

阿里:http://mysql.taobao.org/monthly/2017/06/07/这边文章是以mysql可重复度解决了幻读但此情况还是出现了幻读的角度。我们反过来看mysql是如何通过MVCC解决部分幻读的

mvcc解决幻读

在这个案例中。如果mysql的可重复读不解决幻读问题。哪session1在第二次select中应该是可以查出session2插入的数据的。但是由于MVCC的存在session2的事务id是大于session1中readview的最大事务的所以我们是看不到session2插入的数据的保证了此时的不可幻读。但是记住MVCC只是解决读问题。在update时 讲session2插入的数据的事务id更新成seesion1的事务id了导致最后一次查询数据的事务id==当前事务id变成可见了。

2PL解决部分幻读

美团:https://tech.meituan.com/2014/08/20/innodb-lock.html

mvcc解决幻读

以我们的认知可重复不解决幻读问题此时事务B的数据应该是能插入的但实际上被阻塞了这是因为事务A在执行update的时候加上了间隙锁
mvcc解决幻读

导致此时无法插入需等事务A提交后释放锁2PL第二步才能插入。