miaosha/docs/mysql-mvcc.md
2020-10-09 15:28:32 +08:00

67 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 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; |
![版本变更流程](imgs/mysql-mvcc-1.png)
操作的时候会生成事务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如果被删除了就忽略这条数据
![匹配规则](imgs/mysql-mvcc-2.png)
### 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解决幻读](imgs/mysql-mvcc-3.png)
在这个案例中如果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解决幻读](imgs/mysql-mvcc-4.png)
以我们的认知可重复不解决幻读问题此时事务B的数据应该是能插入的但实际上被阻塞了这是因为事务A在执行update的时候加上了间隙锁
![mvcc解决幻读](imgs/mysql-mvcc-5.png)
导致此时无法插入需等事务A提交后释放锁2PL第二步才能插入