Mysql(InnoDB引擎)--MVCC--多版本并发控制

在数据库事务并发的情况下,会遇到不可重复读的问题

不可重复读就是说事务A需要执行两次查询,这时候一个事务B对事务A两次查询的间隙中把某些行给update了,然后事务A两次读出来的数据就不一样

要解决这样的问题,一般能想到两种办法:将事务要查询的某些行给上锁给数据表添加两个版本字段,创建版本和删除版本

第一种方法效率较低,第二种方法就是MVCC

MVCC只在REPEATABLE READ和READ COMMITED两个隔离级别下工作,其它两个隔离级别下不存在MVCC

实现的原理

数据表的每一行引擎innodb都会添加上创建版本号删除版本号,版本号是递增的,有点类似与git上面每次commit都会有一个版本号,版本号保证是唯一的。

具体操作

select:满足以下两个条件要同时成立innodb才会返回该行数据:(1)该行的创建版本号小于等于当前版本号,用于保证在select操作之前所有的操作已经执行落地。(2)该行的删除版本号大于当前版本或者为空。删除版本号大于当前版本意味着有一个并发事务将该行删除了。

insert:将新插入的行的创建版本号设置为当前系统的版本号。

delete:将要删除的行的删除版本号设置为当前系统的版本号。

update:不执行原地update,而是转换成 delete+insert。将旧行的删除版本号设置为当前版本号,并将新行insert同时设置创建版本号为当前版本号。-->这是构思非常巧妙地

insert,delete,update执行的时候,系统版本号会递增

 

怎么解决不可重复读的呢?

 

比如,事务A要执行两次查询,事务B在事务A查询的两次间隙中对某些数据进行update,假设查询的那几行数据之前都只做过insert,insert会给该行的创建版本给填上初始版本号,然后系统版本号也设置为这个0.0.1,假如是0.0.1,此时我们进行select的话则用系统当前版本号0.0.1与那几行数据的创建版本号也是0.0.1进行比较,很显然,该行的创建版本号要<=系统当前版本号,这样才能保证select之前的操作已经执行完毕,因为我要读的要是最新的数据,如果创建版本号>当前版本号,不就是说select之前的(insert,update)操作将创建版本号给改小了?但是第二个条件无法满足,所以无法读出来

依旧无法解决幻读问题

select才会去判断当前版本号和数据的创建版本号,删除版本号的关系

update只是给旧行打上了标记,但是并没有物理上的删除,所以需要有后台线程将这些删除版本号小于系统当前版本号的行删除

如果要防止幻读的话,MVCC的基础上还需要上锁

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值