java 实现mvcc_传统mvcc和innodb mvcc实现

根据《高性能mysql》一书的描述,mvcc实现应该大致如下:

1、每行数据后面有两个隐藏的字段,一个字段为更新标识,一个字段为删除标识,记录内容为更新/删除时候的系统版本号。

2、select过程中,会根据当前事务版本号去过滤小于等于的数据。

3、update操作实际会新增一行记录,而并非在原数据上修改。

4、delete也并非物理删除,而是在删除标识字段上加上版本号。

听起来蛮不错的,然而innodb的mvcc实现并非如此!!

在innodb中,两个隐藏字段分别为DATA_TRX_ID、DATA_ROLL_PTR(如果没有主键,则还会多一个隐藏的主键列)。

DATA_TRX_ID

记录最近更新这条行记录的事务 ID,大小为 6 个字节

DATA_ROLL_PTR

表示指向该行回滚段(rollback segment)的指针,大小为 7 个字节,InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在 undo 中都通过链表的形式组织,在网上搜了一下,大概格式如下,它记录的是每个版本被修改的数据,并非是一条操作的反操作。

60e25bb5f1a9a487ab64368cde1ee892.png

所以,实际上每次进行update操作时,并非是会创建一个新的副本。而是会先将就的数据行copy进undo log中去,随后修改该数据行,并且修改其DATA_TRX_ID 和 DATA_ROLL_ID。

上面说了支撑mvcc功能的列结构,那么下来看一下mysql的四种事务隔离级别和mvcc的关系。

1.脏读

和mvcc没有关系,每次select最新的数据,别的事务的数据只要已经物理写入或者修改,那么它便会去读,直接忽略掉后面的DATA_TRX_ID。

2.提交读

在mvcc的使用上,innodb引入了ReadView 这一方式。在生成一个ReadView的时候,会收集所有目前所有活跃事务(既还未提交的事务)的版本号到一个队列中m_ids,并且把当前系统版本号+1,也加入队列中。那么就可以找到版本号的最小值up_limit_id和最大值low_limit_id。在select的过程中,对于一条数据,与m_ids对比,会有如下结果。

a.小于up_limit_id,说明该事务在ReadView开启之前已经提交,所以为有效数据。

b.大于low_limit_id,说明该事物是在ReadView开启之后才提交的,为无效数据,这时候就要顺着undo log链表向上查找了,直到找到有效的

c.如果 up_limit_id

ps.在undo log上查找时,并不是只有data_trx_id小于up_limit_id才为有效,满足条件c也是可以的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值