在并发读写数据库时,读操作可能会不一致的数据(脏读)。为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问。由于,加锁会将读写操作串行化,所以不会出现不一致的状态。但是,读操作会被写操作阻塞,大幅降低读性能。在Javaconcurrent包中,有copyonwrite系列的类,专门用于优化读远大于写的情况。而其优化的手段就是,在进行写操作时,将数据copy一份,不会影响原有数据,然后进行修改,修改完成后原子替换掉旧的数据,而读操作只会读取原有数据。通过这种方式实现写操作不会阻塞读操作,从而优化读效率。而写操作之间是要互斥的,并且每次写操作都会有一次copy,所以只适合读大于写的情况。

MVCC的原理与copyonwrite类似,全称是Multi-Version Concurrent Control,即多版本并发控制。在MVCC协议下,每个读操作会看到一个一致性的snapshot,并且可以实现非阻塞的读。MVCC允许数据具有多个版本,这个版本可以是时间戳或者是全局递增的事务ID,在同一个时间点,不同的事务看到的数据是不同的。

实现原理:

------------------------------------------------------------------------------------------> 时间轴

|-------R(T1)-----|

|-----------U(T2)-----------|

如上图,假设有两个并发操作R(T1)和U(T2),T1和T2是事务ID,T1小于T2,系统中包含数据a = 1(T1),R和W的操作如下:

R:read a (T1)

U:a = 2    (T2)

R(读操作)的版本T1表示要读取数据的版本,而之后写操作才会更新版本,读操作不会。在时间轴上,R晚于U,而由于U在R开始之后提交,所以对于R是不可见的。所以,R只会读取T1版本的数据,即a = 1。

由于在update操作提交之前,不能影响已有数据的一致性,所以不会改变旧的数据,update操作会被拆分成insert + delete。需要标记删除旧的数据,insert新的数据。只有update提交之后,才会影响后续的读操作。而对于读操作而且,只能读到在其之前的所有的写操作,正在执行中的写操作对其是不可见的。

上面说了一堆的虚的理论,下面来点干活,看一下MySQL的innodb引擎是如何实现MVCC的。innodb会为每一行添加两个字段,分别表示该行创建的版本删除的版本,填入的是事务的版本号,这个版本号随着事务的创建不断递增。在repeated read的隔离级别(事务的隔离级别请看这篇文章)下,具体各种数据库操作的实现:

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

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

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

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

其中,写操作(insert、delete和update)执行时,需要将系统版本号递增。

由于旧数据并不真正的删除,所以必须对这些数据进行清理,innodb会开启一个后台线程执行清理工作,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫做purge。

通过MVCC很好的实现了事务的隔离性,可以达到repeated read级别,要实现serializable还必须加锁。

MVCC浅析的更多相关文章

  1. MVCC浅析(转)

    在并发读写数据库时,读操作可能会不一致的数据(脏读).为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问.由于,加锁会将读写操作串行化,所以不会出现不一致的状态.但是,读操作会被 ...

  2. 1031MVCC和事务浅析

    转自 http://blog.csdn.net/sofia1217/article/details/50778906 关于MVCC浅析,有些难度http://xuebinbin212.blog.163 ...

  3. mysql MVCC

    InnoDB多版本(MVCC)实现简要分析 MVCC实现-MySQL Innodb MVCC实现 MVCC浅析 mysql的mvcc(多版本并发控制) mysql innodb mvcc 读一致性(R ...

  4. mvcc摘抄

    MVCC浅析原文:---->>>>>> http://blog.csdn.net/chosen0ne/article/details/18093187 在并发读写数 ...

  5. 关于Python的面试题

    Python语言特性 1 Python的函数参数传递 看两个例子: a = 1 def fun(a): a = 2 fun(a) print a # 1 a = [] def fun(a): a.ap ...

  6. 最全python面试题

    Python语言特性 1 Python的函数参数传递 看两个例子: a = 1 def fun(a): a = 2 fun(a) print a # 1 a = [] def fun(a): a.ap ...

  7. python面试题第一份

    阅读目录 1 Python的函数参数传递 2 Python中的元类(metaclass) 3 @staticmethod和@classmethod 4 类变量和实例变量 5 Python自省 6 字典 ...

  8. MySQL多版本并发控制机制(MVCC)-源码浅析

    MySQL多版本并发控制机制(MVCC)-源码浅析 前言 作为一个数据库爱好者,自己动手写过简单的SQL解析器以及存储引擎,但感觉还是不够过瘾.<<事务处理-概念与技术>>诚然 ...

  9. h2database源码浅析:锁与MVCC

    Table Level Locking The database allows multiple concurrent connections to the same database. To mak ...

随机推荐

  1. mysql解压缩版安装方法以及mysql无法启动1067错误

    https://jingyan.baidu.com/article/f3ad7d0ffc061a09c3345bf0.html我下载的版本号是5.6.421.解压到C:\Program Files\M ...

  2. PHP开发——数组

    数组的概念 l  数组是一组数的集合.如:$arr = array(1,2,3,4,5,6) l  标量数据类型是一个值的容器,而数组就是多个值的容器. 数组的分类 l  枚举数组:数组元素的下标(索 ...

  3. 实战Python实现BT种子转化为磁力链接

    经常看电影的朋友肯定对BT种子并不陌生,但是BT种子文件相对磁力链来说存储不方便,而且在网站上存放BT文件容易引起版权纠纷,而磁力链相对来说则风险小一些. 将BT种子转换为占用空间更小,分享更方便的磁 ...

  4. 深拷贝 deepAssign

    实现代码: <script type="text/javascript"> Object.deepAssign = function() { var args = Ar ...

  5. Linux学习笔记:常用软件

    Linux系统下常用软件(针对CentOS,其他系统类似) lrzsz 可用于上传和下载,安装 yum -y install lrzsz ,使用 上传 rz 下载 sz mysql 安装 yum -y ...

  6. Samba简介与配置(匿名&本地用户验证)

    Samba简介 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成. 在此之前我们已经了解了NFS,NFS与samba一样,也是在网络中实现文件共享的一种实 ...

  7. python函数(二)

    python函数(二) 变量的作用域 1.局部变量与全局变量 在函数内创建的变量被称为局部变量,这类变量的生命周期与函数相同,当函数执行完毕时,变量也就随之消失. 此类变量只能在函数内部调用,函数外不 ...

  8. 无网情况下linux安装django

    创建虚拟环境~/project/hanqin/django> virtualenv monitor2~/project/hanqin/django/monitor2> cd bin~/pr ...

  9. Day02 (黑客成长日记)

    #用户登录次数为三代码 # i = 0 # while i < 3: # username = input('请输入账号:') # password = input('请输入密码:') # if ...

  10. bzoj4555(多项式求逆解法)

    //和以前写的fft不太一样,可能是因为要取模?? #include<iostream> #include<cstring> #include<cmath> #in ...