首页 > 其他分享 >MVCC——多版本并发控制

MVCC——多版本并发控制

时间:2023-04-08 09:49:41浏览次数:78  
标签:事务 快照 Read 并发 版本 MVCC ID View

概念

Multi Version Concurrency Control, 用于数据库的并发访问控制

MVCC在mysql innoDB中的实现主要是为了提高数据库并发性能, 用更好的方式去处理读-写冲突, 实现读写冲突不加锁, 非阻塞并发读写

每一次的数据修改都会将历史记录保存在Undo log里, 读数据采用快照读的方式, 这样就不会有阻塞了

什么是当前读和快照读

当前读

共享锁、排他锁 都是保证其他事务不能并发修改当前记录, 所以读取的肯定是最新纪录

快照读

简单理解就是 不加锁的select、快照读的前提是基于多版本控制, 快照读读取的不一定是最新数据, 有可能是某个版本的数据

MVCC能解决什么问题

数据库并发场景有三种,分别为:

  • 读-读:不存在任何问题,也不需要并发控制
  • 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
  • 写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失

MVCC 带来的好处是?
多版本并发控制(MVCC)是一种用来解决读-写冲突无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以 MVCC 可以为数据库解决以下问题

  • 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能
  • 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题

小结一下咯
简而言之,MVCC 就是因为大佬们,不满意只让数据库采用悲观锁这样性能不佳的形式去解决读-写冲突问题,而提出的解决方案,所以在数据库中,因为有了 MVCC,所以我们可以形成两个组合:

  • MVCC + 悲观锁
    MVCC解决读写冲突,悲观锁解决写写冲突
  • MVCC + 乐观锁
    MVCC 解决读写冲突,乐观锁解决写写冲突

MVCC 的实现原理

为了解决**读写冲突,它的实现原理主要是依赖记录中的** 3个隐式字段undo日志 ,Read View 来实现的

隐式字段

1、DB_TRX_ID

6 byte, 最近修改(修改和插入)的事务ID: 创建这条记录/修改这条记录的最后一次事务ID

2、DB*_ROLL_PTR*

7 byte, 回滚指针, 指向这条记录的上一个版本 (指向的是undo log)

3、DB_ROW_ID

6 byte, 隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动以DB_ROW_ID          产生一个聚簇索引
实际还有一个删除 flag 隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除 flag 变了

undo log

undo log 主要分为两种:

1、insert undo log
      代表事务在 insert 新记录时产生的 undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
2、update undo log
      事务在进行 update 或 delete 时产生的 undo log ; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被 purge线程统一清除

	purge
*   从前面的分析可以看出,为了实现 InnoDB 的 MVCC 机制,更新或者删除操作都只是设置一下老记录的 deleted\_bit ,并不真正将过时的记录删除。
*   为了节省磁盘空间,InnoDB 有专门的 purge 线程来清理 deleted\_bit 为 true 的记录。为了不影响 MVCC 的正常工作,purge 线程自己也维护了一个read view(这个 read view 相当于系统中最老活跃事务的 read view );如果某个记录的 deleted\_bit 为 true ,并且 DB\_TRX\_ID 相对于 purge 线程的 read view 可见,那么这条记录一定是可以被安全清除的。

Read View 读视图

说白了 Read View 就是事务进行 快照读 操作的时候生产的 读视图 (Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID (当每个事务开启时,都会被分配一个 ID , 这个 ID 是递增的,所以最新的事务,ID 值越大)

Read View 遵循一个可见性算法,主要是将 要被修改的数据 的最新记录中的 DB_TRX_ID(即当前事务 ID )取出来,与系统当前其他活跃事务的 ID 去对比(由 Read View 维护),如果 DB_TRX_ID 跟 Read View 的属性做了某些比较,不符合可见性,那就通过 DB_ROLL_PTR 回滚指针去取出 Undo Log 中的 DB_TRX_ID 再比较,即遍历链表的 DB_TRX_ID(从链首到链尾,即从最近的一次修改查起),直到找到满足特定条件的 DB_TRX_ID , 那么这个 DB_TRX_ID 所在的旧记录就是当前事务能看见的最新老版本

MVCC 相关问题

RC , RR 级别下的 InnoDB 快照读有什么不同?

RC: 读已提交 RR: 可重复读

正是** Read View** 生成时机的不同,从而造成 RC , RR 级别下快照读的结果的不同

  • 在 RR 级别下的某个事务的对某条记录的第一次快照读会创建一个快照及 Read View, 将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个 Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个 Read View,所以对之后的修改不可见;
  • 即 RR 级别下,快照读生成 Read View 时,Read View 会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
  • 而在 RC 级别下的,事务中,每次快照读都会新生成一个快照和 Read View , 这就是我们在 RC 级别下的事务中可以看到别的事务提交的更新的原因
  • 总之在 RC 隔离级别下,是每个快照读都会生成并获取最新的 Read View;而在 RR 隔离级别下,则是同一个事务中的第一个快照读才会创建 Read View, 之后的快照读获取的都是同一个 Read View。

参考资料:

https://blog.csdn.net/bbj12345678/article/details/120780051

【【MySql】理解Read View(事务 undolog MVCC)】 https://www.bilibili.com/video/BV1A24y187ss/?share_source=copy_web&vd_source=95687cb0a9238b1e583346db070aefae

标签:事务,快照,Read,并发,版本,MVCC,ID,View
From: https://www.cnblogs.com/liyong888/p/17297927.html

相关文章

  • 【并发编程】Java7 - ForkJoin,将大任务拆分成小任务
    1.简介  Java7提供了可以将大任务拆分成小任务执行再合并结果的框架——Fork/Join。其中,将大任务拆分成足够执行的小任务并发执行的过程称为Fork,将这些小任务结果整合后形成最终的结果的过程称为Join。  Fork/Join框架的具体体现为ForkJoinTask抽象类,该类继承了Future,运行......
  • 【Java 并发】【九】【AQS】【八】ReentrantReadWriteLock 读写锁怎么表示
    1 前言接下来我们来看看ReentrantReadWriteLock读写锁,也是基于之前讲解的AQS来实现的,建立在AQS体系之上的一个并发工具类,这个锁很重要,在很多开源的中间件中使用的非常广泛,很多场景使用它来减少并发操作中的锁冲突,提升并发能力。2  ReentrantReadWriteLock介绍ReentrantRead......
  • flask-day5——python项目高并发异步部署、uwsgi启动python的web项目不要使用全局变量
    目录一、python项目高并发异步部署二、uwsgi启动Python的Web项目中不要使用全局变量三、信号3.1flask信号3.2django信号四、微服务的概念五、flask-script六、sqlalchemy快速使用七、sqlalchemy快速使用4.1原生操作的快速使用八、创建操作数据表九、作业1、什么是猴子补丁,有什......
  • django/flask高并发部署
    django和flask是同步框架,部署的时候使用uwsgi部署,uwsgi是多进程多线程框架,并发量不高大概几十。我们可以通过uwsgi加gevent部署成异步程序,普通的部署方式uwsgi-x./luffyapi.xml这是使用genvent提高并发部署uwsgi--gevent50--gevent-monkey-patch./luffyapi.xml......
  • Java多版本切换 8-11-17
    Java版本切换在A:\DevEnvironment\javaVersion目录下,创建Windows命令脚本Java8.bat @echooff setJAVA_HOME=A:\DevEnvironment\jdk-1.80_152 setPath=%JAVA_HOME%\bin;%Path% echoVersionhasbeenswitchedtoJava8.Java11.bat @echooff setJAVA_HOME=A:\DevE......
  • 上传了ipa但在苹果App Store中没有看到构建版本的问题
     AU上传ipa出现下图红框提示说明成功上传,但有时AppStore后台没有出现构建版本,请查看下面详细说明!编辑 一、首先登录iTunesConnect后台、查看ipa构建情况https://appstoreconnect.apple.com/点击进入APP,点击活动,所有构建版本选项(下图所示),有两种情况!1、ipa包符合要求,显示正在处......
  • linux系统升级/更新OpenSSL版本操作流程记录
    问题描述:有时OpenSSL版本过老升级,或者需要更新OpenSSL版本1.登录linux系统后输入opensslversion查看现在使用的版本我的输入后版本信息为:OpenSSL1.1.1gFIPS 21Apr2020,可以看到是一年前更新版本,是有些老。2.登录openssl官网查看最新版本。登录https://www.openssl.org......
  • 上传了ipa但在苹果App Store中没有看到构建版本的问题
    ​ AU上传ipa出现下图红框提示说明成功上传,但有时AppStore后台没有出现构建版本,请查看下面详细说明!​编辑  一、首先登录iTunesConnect后台、查看ipa构建情况https://appstoreconnect.apple.com/点击进入APP,点击活动,所有构建版本选项(下图所示),有两种情况!1、ipa包符......
  • Go RWMutex:高并发读多写少场景下的性能优化利器
    原创文章,如需转载请联系作者:陈明勇公众号:Go技术干货前言在这篇文章GoMutex:保护并发访问共享资源的利器中,主要介绍了Go语言中互斥锁Mutex的概念、对应的字段与方法、基本使用和易错场景,最后基于Mutex实现一个简单的协程安全的缓存。而本文,我们来看看另一个更高效的......
  • JUC并发编程第十四章之StampedLock(读写锁的优化实践)
    JUC并发编程学习路线JUC并发编程第一章之进程/并发/异步的概念[理解基本概念]JUC并发编程第二章之CompletableFuture[加强版的线程]JUC并发编程第三章之Synchronized八锁案例[理解锁的对象]JUC并发编程第四章之公平锁/重入锁/死锁[常见锁的基本认识]JUC并发编程第五章之线程......