MVCC实现原理详解

MYSQL MVCC实现原理详解

MVCC(Multi Version Concurrency Control的简称),代表多版本并发控制。与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。 就是乐观锁的一种实现方式。在Java编程中,如果把乐观锁看成一个接口,MVCC便是这个接口的一个实现类而已。

MVCC最大的优势:读不加锁,读写不冲突。在读多写少的 OLTP 应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能

数据库默认隔离级别:RR(Repeatable Read,可重复读),MVCC主要 适用于Mysql的RC,RR隔离级别

不可重复读(read-committed)

OLTP与OLAP的概念以及区别是什么?

一、两者的概述不同:

1、OLTP的概述:On-Line Transaction Processing 联机事务处理过程(OLTP),也称为面向交易的处理过程。

2、OLAP的概述:联机分析处理OLAP是一种软件技术,它使分析人员能够迅速、一致、交互地从各个方面观察信息,以达到深入理解数据的目的。

img

二、两者的特点不同:

1、OLTP的特点:结构复杂、实时性要求高。

2、OLAP的特点:联机分析处理的主要特点,是直接仿照用户的多角度思考模式,预先为用户组建多维的数据模型,维指的是用户的分析角度。

三、两者的用户不同:

1、OLTP的用户:操作人员,低层管理人员。

2、OLAP的用户:决策人员,高级管理人员。

特点

1.MVCC其实广泛应用于数据库技术,像Oracle,PostgreSQL等也引入了该技术,即适用范围广

2.MVCC并没有简单的使用数据库的行锁,而是使用了行级锁,row_level_lock,而非InnoDB中的innodb_row_lock.

基本原理

MVCC的实现,通过保存数据在某个时间点的快照来实现的。这意味着一个事务无论运行多长时间,在同一个事务里能够看到数据一致的视图。根据事务开始的时间不同,同时也意味着在同一个时刻不同事务看到的相同表里的数据可能是不同的。

MVCC实现

MVCC是通过在每行记录后面保存两个隐藏的列来实现的。 这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间) 。当然存储的并不是实际的时间值,而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

repeatable-read 隔离级别下,MVCC具体是如何操作的

  • Select

    InnoDB会根据以下两个条件检查每行记录:

    • InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
    • 行的删除版本要么未定义,要么 大于当前事务版本号 。这可以确保事务读取到的行,在事务开始之前未被删除。

    只有符合上述两个条件的记录,才能返回作为查询结果

  • insert

    InnoDB为新插入的每一行保存当前系统版本号作为行版本号。

  • delete

    InnoDB为删除的每一行保存当前系统版本号作为行删除标识。

  • update

    InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
    保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作

举例说明
 create table mvcctest(  id int primary key auto_increment,  name varchar(20)); 

transaction 1:

start transaction; 
insert into mvcctest values(NULL,'mi');
insert into mvcctest values(NULL,'kong');
commit; 

假设系统初始事务ID为1;

IDNAME创建时间过期时间
1mi1undefined
2kong1undefined

transaction 2:

start transaction;
select * from mvcctest;  //(1)
select * from mvcctest;  //(2)
commit
SELECT

假设当执行事务2的过程中,准备执行语句(2)时,开始执行事务3:

transaction 3:

start transaction;
insert into mvcctest values(NULL,'qu');
commit;
IDNAME创建时间过期时间
1mi1undefined
2kong1undefined
3qu3undefined

事务3执行完毕,开始执行事务2 语句2,由于事务2只能查询创建时间小于等于2的,所以事务3新增的记录在事务2中是查不出来的,这就通过乐观锁的方式避免了幻读的产生

UPDATE

假设当执行事务2的过程中,准备执行语句(2)时,开始执行事务4:

transaction session 4:

start transaction;
update mvcctest set name = 'fan' where id = 2;
commit;

InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的行的删除时间

IDNAME创建时间过期时间
1mi1undefined
2kong14
2fan4undefined

事务4执行完毕,开始执行事务2 语句2,由于事务2只能 查询创建时间小于等于2的 ,所以事务修改的记录在事务2中是查不出来的,这样就保证了事务在两次读取时读取到的数据的状态是一致的

DELETE

假设当执行事务2的过程中,准备执行语句(2)时,开始执行事务5:

transaction session 5:

start transaction;
delete from mvcctest where id = 2;
commit;
IDNAME创建时间过期时间
1mi1undefined
2kong15

事务5执行完毕,开始执行事务2 语句2,由于事务2只能查询创建时间小于等于2、并且过期时间大于等于2,所以id=2的记录在事务2 语句2中,也是可以查出来的,这样就保证了事务在两次读取时读取到的数据的状态是一致的

补充:

1.MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read).

2.Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.

​ 原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。

3.串行化由于是会对所涉及到的表加锁,并非行锁,自然也就不存在行的版本控制问题。

4.通过以上总结,可知,MVCC主要作用于事务性的,有行锁控制的数据库模型

切记:

第一个SELECT执行的时候,当前事务取到了系统版本号n(并不是begin的时候就生成版本号,而是执行事务内第一个语句时生成),系统版本号自增为n+1。 此后,其他事务的更新操作能取到的系统版本号最小为n+1,所以当前事务再次SELECT将看不见它们的更新 ,(其实就是事务1之后,再执行的事务2,对数据进行修改,事务1再select是看不到的)。

其主要依靠版本控制,即消除锁定,二者相互矛盾,so从某种意义上来说,Mysql的MVCC并非真正的MVCC,他只是借用MVCC的名号实现了读的非阻塞而已

寄语:
在这里插入图片描述
谢谢支持!在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会敲代码的泡椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值