简介:
大家好,我是xp,我又诈尸了
mvcc
,想必大家都不陌生,每个Java程序员都或多或少的了解过,不过不知道大家都是怎么学习的,是不是简单的百度一下呢?下面,我来带大家装个13,调试mvcc
。咳,不是源码哈,但有那味了。
开卷开卷。
首先介绍一下mvcc
的字面意思,全称:Multiversion Concurrency Control,翻译下来就是多版本并发控制技术。
脏读、不可重复读、幻读的概念就不多啰嗦了,mvcc
具体的含义也不多啰嗦了,可以自行百度。mvcc
解决了脏读、不可重复读、部分幻读,包含了3个重要成分:
- undo log
- 3个隐式字段
- Read View
undo log作用:
- 回滚
- 多个行版本控制
在数据修改的时候,不仅记录了redo log,还记录了undo log。但是不同于redo log,undo log是逻辑日志。简单理解成,delete的时候,undo log会出现一条insert,update的时候,undo log会出现一条旧数据,用来事务失败之后的回滚。
3个隐式字段:
- DB_ROW_ID:行id
- DB_TRX_ID:事务id
- DB_ROLL_PTR:回滚指针
Read View:
m_creator_trx_id:事务id
m_low_limit_id:= max_trx_id:全局变量,每次分配的事务id,就是这个id,用完+1
m_up_limit_id:m_ids的第一个事务id,m_ids是升序列表
m_ids:创建该Read View时的活跃事务id列表
好了,理论讲完了,让我们嗨起来。
嗨之前,有一个情况单独说一下:
可以看到,此时的trx_id非常大,这是因为此时是只读事务。对于只读事务,InnoDB 并不会分配 trx_id,只有发生dml才会分配。这样有2个好处:
- 减少活跃事务的数量
- 减少 trx_id 的申请次数
至于这2个好处具体的作用,这里就不细说了,想知道的可以百度或者留言。
当commit了之后,我们使用SHOW ENGINE INNODB STATUS查看:
可以看到,显示该事务并没有开始。
好,回到正轨,相信大家都知道,视图可见性判断(不知道的先百度mvcc
):
- trx_id = m_creator_trx_id,可见
- trx_id < m_up_limit_id,可见
- trx_id >=m_low_limit_id,不可见
- m_up_limit_id < trx_id < m_low_limit_id,需要判断在不在m_ids里面
整体是这样的:
第一步我们以38488
为开始值,把name
更新成111
,并且commit
第二步以38490
把name
更新成222,333
,但是不commit
当38490
第一次修改为222
的时候,数据结构大致是这样的:
使用SHOW ENGINE INNODB STATUS
侧面验证:
当38490
第二次修改为333
的时候,数据结构大致是这样的:
使用SHOW ENGINE INNODB STATUS
侧面验证:
第三步以38491
去查询,此时生成的m_ids
应该是[348490,38491]
使用SHOW ENGINE INNODB STATUS
侧面验证:
此时ReadView
的几个属性值为:
- m_creator_trx_id:38491
- m_low_limit_id:38492
- m_up_limit_id:348490
- m_ids:[348490,38491]
接下来我们来验证结论:
1:不用验证,当前事务修改的肯定自己可见
2:38491查询id=1的记录,name为111
38488 < 348490,所以111可见
3:不用验证,38492是下个事务的id,还没生成呢,当前事务,肯定看不见下个事务修改的值
4:我们先把38491commit,把id为20的name更新成111
然后再开一个事务38496:
此时查id为20,是可见的
m_ids:[348490,38496],因为38491已经commit了,所以m_ids没有。此时的38491在m_ids之间,但是在m_ids里面找不到,所以可见。
好了,愉快的装13结束了,兄弟们,下次见。