事务隔离级别的无锁实现方式 -- MVCC

2024-04-15 05:28

本文主要是介绍事务隔离级别的无锁实现方式 -- MVCC,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MVCC的全称是Multiversion Concurrency Control(多版本并发控制器),是一种事务隔离级别的无锁的实现方式,用于提高事务的并发性能,即事务隔离级别的一种底层实现方式。

在了解MVCC之前,我们先来回顾一些简单的知识点:数据库的隔离级别和并发场景。

数据库的隔离级别

主要用来解决多个事务在并发的情况下对同一个数据进行读写操作所产生的一些列线程不安全的问题。

  • 脏读 – 读未提交(RU)
    • 事务A读取到了事务B还未提交的数据。
  • 不可重复读 – 读已提交(RC)
    • 事务A读取到事务B已经提交的数据,可以解决脏读问题,但会出现不可重复读。
  • 可重复读(RR)
    • 同一是事务下,事务在执行期间,多次读取同一数据时,能够保证读取到的数据是一致的,可以解决不可重复读问题,但在事务读取过程中,如果有另外一个新事务新增/变更,会出现幻读。
  • 串行化(serializable)
    • 最高的隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读,幻读和不可重复读的问题,但是这种事务隔离级别效率最低,比较耗费数据库性能。

读已提交:

解决脏读问题为什么不使用行锁?如果我们在事务一中对数据进行修改操作时给数据添加一个行锁,那么接下来的事务中想要执行SQL语句进行查询操作,那么该操作将会被阻塞,直到修改操作执行完毕,行锁被解开为止,如此一来,就会降低并发性。

三种并发场景

  • 读 - 读
    • 不存在线程安全问题,不需要关心并发
  • 读 - 写
    • 有线程安全问题,可能会存在数据更新丢失的问题,比如第一类更新丢失,第二类更新丢失

第一类更新丢失:事务A回滚时,将已经提交的事务B更新的数据覆盖了

第二类更新丢失:事务A提交覆盖了事务B已经提交的数据,造成事务B所做的操作丢失

什么是MVCC

定义

即多版本并发控制,是一种并发控制的方法,一般在数据库管理系统中实现对数据库的并发访问,在编程语言中实现事务内存。

目的

在最早的数据库系统中只有读 - 读之间可以并发,读 - 写、写 - 写之间都要阻塞。在引入多版本并发控制技术之后,只有写 - 写之间相互阻塞,其他三种操作都可以并行,这样就达到了提高InnoDB引擎并发度的目的。

实现

在MySQL的内部实现中,InnoDB是通过undo log实现,undo log可以找回数据的历史版本。找回的历史版本可以提供给用户读(按照隔离级别定义,有些读请求只能看到比较老的数据版本),也可以在回滚的时候覆盖数据页上的数据,在InnoDB内部中,会记录一个全局的活跃读写事务数据组,其主要用来判断事务的可见行

MVCC的三个关键点

MVCC是如果无锁地实现事务的隔离级别的呢?主要就是靠以下三个关键因素:

隐藏列

在数据库表单中除了我们创建的原数据的列外,数据库帮我们维护的三个看不到的隐藏列:DB_TRX_ID(事务ID),DB_TRX_ID(存储旧的事务的指针),(ROW_ID)
在这里插入图片描述

undo log

回滚实现:

通过两个隐藏列trx_id(最近一次提交事务的ID)和roll_pointer(上个版本的地址)建立一个版本链。并在事务中读取的时候生成一个Read View(读视图),在Read Committed隔离级别下,每次读取都会生成一个读视图,而在Repeatable Read隔离级别下,只会在第一次读取时生成一个读视图

在这里插入图片描述

ReadView

定义

不加锁的select就是快照读,即不加锁的非阻塞读。(快照读的前提是非serializable隔离级别,在该隔离级别下,快照读会退化为当前读),之所以出现快照读,是基于高并发性能的考虑,快照读的实现是基于MVCC的,可以认为MVCC是行锁的变种,但是他在很多情况下避免了加锁操作,降低了开销。因为多版本的原因,导致快照读可能读取到的不一定是数据的最新版本,而有可能是历史版本

当前读和快照读与MVCC关系

MVCC可以理解为是一个“维护数据的多个版本,使得读写操作没有冲突”的概念,是一种理想状态。而在MySQL中,快照读,就是实现MVCC理想模型的其中一个具体的非阻塞读功能,而相对而言,当前读就是一个悲观锁的具体功能实现

具体实现&&判断顺序

存储三条数据:creator_trx_id(当前事务ID),min_trx_id(当前未提交的事务的ID),max_trx_id(未开始的事务)

  • 首先通过undolog拿到最新版本的数据,最新一次修改本条数据的事务ID
  • 第一次判断:将当前事务ID与最新一次修改本条数据的事务ID进行比较
    • 二者相等–>本条版本的数据是在当前事务中保存的–>该条数据可以读取
    • 二者不相等则不能直接拿到该值,继续进行判断
  • 第二次判断:比较最新一次修改本条数据的事务ID和最小的事务ID
    • 小于–>当前版本数据是在事务开始之前保存的–>该条数据可以读取到
    • 大于等于–>不能直接拿到该值,继续进行判断
  • 第三次判断:比较最新一次修改本条数据的事务ID和最大的事务ID
    • 大于–>当前版本的数据是在本事务开始之后保存的–>本数据不能被读取–>顺着指针找到上一个版本的数据
  • 第四次判断:比较最新一次修改本条数据的事务ID是否在最小事务ID和最大事务ID之间
    • 存在于二者之间–>当前版本的数据是在未提交的并发事务中
      • 如果事务隔离级别是读已提交–>该条数据不能被读取
    • 不存在于二者之间–>沿着指针找到上一个版本的数据,再进行以上四次判断

这篇关于事务隔离级别的无锁实现方式 -- MVCC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/904944

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、