Mysql系列(四)彻底理解MVCC+行锁+表锁+间隙锁

2023-11-10

一. 什么是MVCC

MVCC(Multi-Version Concurrency Control),即多版本并发控制。不使用锁,主要是用来提高数据库的并发性能;算是一种概念,不同的数据库有不同的实现方式,本文主要介绍mysql的innodb引擎中的实现方式。

在mysql的innodb中,前面我们有篇文章《Mysql系列(二)Mysql事务四大隔离级别详解&演示》分析了4种隔离级别,以及每种隔离级别下导致的问题,脏读、不可重复读、幻读。其中不可重复读、幻读就是使用MVCC来解决的。

二.什么是行锁、表锁、间隙锁

首先锁的存在,目的是为了在并发场景下,保持数据的安全、一致。
并发场景有:

  • 读-读 :此并发场景不需要进行并发控制,也就是不需要加锁。
  • 读-写 :此并发场景需要并发控制,不然就会出现脏读,幻读,不可重复读的问题。
  • 写-写 :此并发场景需要并发控制,不然就会出现更新丢失的问题。

进行并发控制,常规手段就是加锁,不管是咋java业务代码中,还是mysql数据库本身,都有实现自己的锁,其中mysql的锁有以下几种:

  • 行锁:锁住表中的一行;比如 update user set name=‘张三’ where id=1;会锁住id=1的那一行数据,其他事务再想更新,就只能等前一个事务释放锁。
  • 表锁:锁住整个表,比如update user set name=‘张三’;由于没有加where条件,此更新sql会对整个表进行更新,也就是会锁住整个表。
  • 间隙锁:比如事务A执行update user set name=‘张三’ where id >1 and id<4; 假如表中只有id=1、2 两条数据,A事务还没提交,那么此时事务B再次插入一条id=3的数据,理论上是允许的,但是实际上是B只能等A提交,因为事务A执行的是id>1and id<4,范围涵盖了id=3的,也即是把id=3的这个间隙也给锁了,叫做间隙锁

除了这3种锁,还有乐观锁、悲观锁、记录锁、自增锁、意向锁;

三. MVCC与各种锁的关系

既然可以使用行锁、表锁、间隙锁来保证数据操作的安全性,那么还要MVCC的出现是为何呢? 实际是因为在性能方面还有优化的空间

虽然使用锁可以保证数据安全,但是毕竟加了锁就意味着并发性能的降低,因此,能不使用锁就尽量不使用锁。在某些场景下,MVCC可以在比使用锁更快。

在读-读、读-写、写-写这3种并发场景中,读-写 可以不使用锁,而是使用MVCC来实现数据的并发操作以及安全一致性

因此,mysql是同时使用了MVCC+行锁、表锁、间隙锁来保证了数据安全,又尽可能大的实现了性能最优化。

四. MVCC的实现原理

4.1 多版本

那么不使用锁,MVCC是如何更高效的解决读-写这种并发场景下的数据安全呢?
我们知道,事务在执行失败时,会将数据回滚为上个版本,而MVCC叫做多版本并发控制,核心概念就在版本上,也就是说数据库存储了多个版本的数据。

多个版本整体上分为两类:最新版本历史版本
这也牵扯出来另外两个概念:

  • 快照读:读取的是数据库种历史版本的数据;
    常规的select * from user ;属于是快照读;
  • 当前读:读取的是数据库种最新版本的数据;当前读的操作有:
    select * from user in share mode(共享锁),;
    select * from user for update;
    update, insert ,delete(排他锁)

那么多个版本,mysql是如何存储的呢?

innodb存储引擎中,我们存在表中的数据,除了我们设置的业务字段,另外还有3个默认字段,如下图末尾3个:
在这里插入图片描述

  • DB_TRX_ID: 事务id,存的是创建事务的id,或者最后一次更新事务的id;
  • DB_ROW_ID: 主键id,建表时如果没设置主键,则此字段会成为主键发挥作用;
  • DB_ROLL_PTR: 回滚指针,指向上一个版本的数据,如果没有上个版本,则为null。

其中,DB_ROLL_PTR结合undo log实现。

4.2 undo log

undo log称为回滚日志,是InnoDB MVCC事务特性的重要组成部分,存在形式就是一种日志文件。

undo log的数据结构,非常复杂,可以简单理解为链表,链表头部存储最新版本,尾部存储最早版本。通过遍历链表,就可以找到对应版本的数据。
在这里插入图片描述
大多数对数据的变更操作包括INSERT/DELETE/UPDATE,其中,

  • INSERT操作使用insert_undo,因为新插入就只有一个版本,因此产生的Undo日志可以在事务提交后直接删除;
  • 而对于UPDATE/DELETE则需要维护多版本信息,在InnoDB里,UPDATE和DELETE操作产生的Undo日志被归成一类,即update_undo;mvcc使用的undolog,就是update_undo。

只有undolog,还不足以实现mvcc,因为既然undolog维护了那么多版本,遍历的时候,应该去找哪一个版本呢?这里必然牵扯到一种规则,这种规则在不同的数据库隔离级别下是不一样的。

innodb具体实现的时候,使用了一种叫做readview的定西。

4.2 readview

readview称为读视图,是事务在进行快照读的时候产生的,算是一种数据结构。

readview中包含3个参数:

  • trx_list :系统活跃的(事务在执行,还没有提交)事务id列表;
  • up_limit_id :trx_list列表中最小的事务id;
  • low_limit_id :ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1;比如当前事务id已经分配到了4,那么low_limit_id的值就是5;

每个事务在进行自己的快照读时,都会产生自己事务对应的readview。

例如下图中:
在这里插入图片描述
有4个事务同时在执行,事务id分别为1,2,3,4;其中,1,2,3还没有提交,4已经提交,那么当事务2在进行快照读时,产生一个readview,其trx_list存的就是活跃的1,2,3,如下图:
在这里插入图片描述
此时,最小的事务id是1,最大的事务id是5 (尚未分配的下一个id),当前最新的事务id是4 (事务4的id)。

可见性算法
上图中右侧黄色部分就是本次查询到底该取哪个版本数据的规则,也叫可见性算法;

查找过程:
遍历undolog的最新数据到最老数据,逐个判断每条log的事务id,当作DB_TRX_ID,然后使用上图中黄色可见性算法比对,最终确定当前遍历的数据是不是目标数据。

读视图的产生时机
在不同的隔离级别下,readview产生的时机是不同的:

  • RC :每次进行快照读的时候,都会产生新的readview;
  • RR :只有在第一次进行快照读的时候,才会产生readview,之后的操作都会使用第一次生成的readview。如果此事务中间发生了update等当前读操作,也会生成新的readview。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql系列(四)彻底理解MVCC+行锁+表锁+间隙锁 的相关文章

  • 如何在不超时的情况下解析大型 CSV 文件?

    我正在尝试解析 50 MB 的 csv 文件 文件本身很好 但我正在尝试解决所涉及的大量超时问题 每个设置上传明智 我可以轻松上传并重新打开文件 但浏览器超时后 我收到 500 内部错误 我的猜测是我可以将文件保存到服务器上 打开它并保留我
  • Java 从 SQL 数组获取 ResultSet 失败

    我试图从数据库中检索电子邮件地址 但没有成功 我的代码如下 Main System out println PortfolioData getEmails 58 So Far Returning null 投资组合数据 public sta
  • 通过我的java代码导出数据库

    我想使用我的 java 代码导出我的 MySQL 数据库 但我还没有找到任何办法 我想要做的就是我的应用程序中有一个按钮作为 导出数据库 单击该按钮时 我的数据库应导出到指定的路径 我使用了以下代码 但它不起作用 Runtime runti
  • 通过货币换算获取每种产品类型的最低价格

    我想选择每种产品类型中最便宜的 包括运费 价格转换为当地货币 最便宜 产品 价格 产品 运费 seller to aud 我的数据库有如下表 PRODUCTS SELLERS id type id seller id price shipp
  • C#:SQL 查询生成器类

    在哪里可以找到好的 SQL 查询构建器类 我只需要一个简单的类来构建 SQL 字符串 仅此而已 我需要它用于 C 和 MySql 我真的不需要像 Linq 或 NHibernate 这样的东西 谢谢 由于 Google 将我引导至此页面 我
  • mySQL MATCH 跨多个表

    我有一组 4 个表 我想对其进行搜索 每个都有全文索引 查询可以使用每个索引吗 CREATE TABLE categories id int 5 unsigned NOT NULL auto increment display order
  • MySQL 全文搜索不适用于某些单词,例如“house”

    我已经在 3 个字段中的一小部分记录上设置了全文索引 也尝试了 3 个字段的组合 并得到了相同的结果 有些单词返回结果很好 但某些单词如 house 和 澳大利亚 不这样做 有趣的是 澳大利亚 和 家乡 这样做 这似乎是奇怪的行为 如果我添
  • 社交应用程序的数据库设计和优化注意事项

    通常的情况 我有一个简单的应用程序 允许人们上传照片并关注其他人 因此 每个用户都会有类似 墙 或 活动源 的东西 他或她可以在其中看到他 她的朋友 他或她关注的人 上传的最新照片 大多数功能都很容易实现 然而 当涉及到这个历史活动源时 由
  • 显示表 FULLTEXT 索引列

    我希望运行一个查询 该查询将返回表中全文索引的列列表 该表采用 MyISAM 格式 我将使用 php 来构建查询 理想情况下 我会运行查询 它会返回信息 以便我可以构造一个以逗号分隔的列字符串 例如 名 姓 电子邮箱 这在 MySQL 中可
  • PDO SQLSRV 和 PDO MySQL 在获取 int 或 float 时返回字符串

    当您获取时 PDO MS SQL Server 和 PDO MySQL 都会返回一个字符串数组 即使列的 SQL 类型本应是数字类型 例如 int 或 float 我设法解决了这个问题 但我想了解为什么它们一开始就这样设计 是不是因为PDO
  • MYSQL - 查找最近的前一天

    我可以以某种方式 不使用 PHP 找到一周中最近的前一天日期吗 Like 最近的上一个星期二的日期是哪一天 CURDATE INTERVAL WEEKDAY CURDATE wday IF WEEKDAY CURDATE gt wday 0
  • Hibernate 对集合的查询过滤器

    我想执行以下查询 from Item i where i categoryItems catalogId catId 然而 这会产生以下异常 非法尝试取消引用集合 所以我用谷歌搜索 找到了这个 Hibernate 论坛帖子https for
  • 截断 Mysql 表 Cron 作业?

    我在如何使用 cron 作业截断 Mysql 表时遇到了一些麻烦 无论我尝试什么 我似乎都无法让数据库清除表格 感谢您的帮助 mysql uderp example pexample hlocalhost Dexample e TRUNCA
  • MYSQL 区分大小写的 utf8 搜索(使用 hibernate)

    我的登录表具有 utf8 字符集和 utf8 排序规则 当我想要检查用户名并检索该特定用户名的其他信息时 hql 查询会为我提供小写和大写相同的结果 我应该如何处理适用于案例的 HQL 查询 我使用 Mysql 5 和 java hiber
  • 为什么我的 if 语句没有按我预期的方式工作?

    我正在尝试实现以下目标 我向我的 SQL 数据库询问使用SELECT FROM subjects 这样做之后我要求使用数组mysqli fetch assoc 在那之前一切都很好 现在的问题是 当我尝试在每个循环中修改 genero 的值
  • 无法通过套接字“/var/lib/mysql/mysql.sock”连接到本地 MySQL 服务器 (2)

    当我尝试连接 mysql 时出现以下错误 Can t connect to local MySQL server through socket var lib mysql mysql sock 2 这个错误有解决办法吗 其背后的原因可能是什
  • 使用 PHP 的 MySQL 连接字符串

    我正在尝试通过本地计算机连接到托管在我的服务器上的数据库 我的服务器有cPanel 11 它是一个典型的共享服务器 由CentOS提供支持 安装了PHP和MySQL 准确地说 我在同一台服务器上持有经销商帐户 我想在不同帐户或域之间访问数据
  • 如何在Sequelize中设置查询超时?

    我想看看如何在 Sequelize 中设置查询的超时时间 我查看了 Sequelize 文档以获取一些信息 但我找不到我要找的东西 我发现的最接近的是 pools acquire 选项 但我不想设置传入连接的超时 而是设置正在进行的查询的超
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • MySQL 按重复项从上到下排序

    我有一个lammer问题 因为我不是mysql专业人士 我有类似的字段 id color 1 red 2 green 3 yellow 4 green 5 green 6 red 我想按重复项进行分组 最常见的重复项先进行分组 所以应该这样

随机推荐

  • 服务器上创建Python虚拟环境

    应用场景 不同的项目 或者同一项目的不同版本 需要安装不同的Python解释器和依赖库 对于有python版本依赖的程序来说 为了安全可靠的管理环境 需要创建不同版本的 独立 隔离 的虚拟环境 virtualenv 是一个创建隔绝的Pyth
  • Java设计与实现“秒杀”活动之抢粽子【完整版】

    五月榴花妖艳烘 绿杨带雨垂垂重 五月新丝缠角粽 金盘送 生绡画扇盘双凤 正是浴兰时节动 正值端午佳节 实习公司也是例行放假三天以及给每一位员工发放了节日小礼品 过完端午又将迎来618活动专场 秒杀抢单活动也是此起彼伏 从而产生刺激性消费 由
  • 使用HiBurn烧录鸿蒙.bin文件到Hi3861开发板

    使用HiBurn烧录鸿蒙 bin文件到Hi3861开发板 鸿蒙官方文档的 Hi3861开发板第一个示例程序 中描述了 如何使用DevEco Device Tool工具烧录二进制文件到Hi3861开发板 本文将介绍如何使用HiBurn工具烧录
  • 网站服务器放本地还是云上,服务器放本地还是云上安全

    服务器放本地还是云上安全 内容精选 换一换 在弹性云服务器上安装完成后输入公网IP 无法连接目的虚拟机 端口无法访问工具 源端网络未连通目的端 目的端安全组未开放8084端口 目的端网络ACL禁用了8084端口 登录源端服务器后 在源端服务
  • Leetcode 计算质数 -- 埃氏筛、线性筛解析

    0 题目描述 leetcode原题链接 204 计数质数 1 埃氏筛 很直观的思路是我们枚举每个数判断其是不是质数 枚举没有考虑到数与数的关联性 因此难以再继续优化时间复杂度 介绍一个常见的算法 该算法由希腊数学家厄拉多塞 Eratosth
  • C语言/实现MD5加密

    本文详细视频讲解 已经发布到B站 https www bilibili com video BV1uy4y1p7on 更多仔细 请关注公众号 一口Linux 一 摘要算法 摘要算法又称哈希算法 它表示输入任意长度的数据 输出固定长度的数据
  • C语言头文件路径相关问题总结说明

    聊聊系统路径位置 绝对路径与相对路径 正斜杠 与 反斜杠 使用说明 by 矜辰所致 目录 前言 一 C语言中的头文件引用 二 KEIL 中的头文件路径 2 1 IncudePaths 指定的路径 绝对路径和相对路径 正斜杠 与 反斜杠 与双
  • SpringBoot Sleuth Zipkin Dubbo日志链路追踪全流程(2)

    SpringBoot SpringCloud Sleuth Zipkin Dubbo日志链路追踪全流程 看这篇文章之前 你最好看一下 之前的文章 SpringBoot SpringCloud Sleuth Zipkin Http Log4j
  • RC电路(一):微分

    1 充放电时间常数 在模拟 数字电路中 常常用到由电阻 和电容 组成的 电路 和 的取值不同 会导致输出波形和输入波形之间的关系也不同 由此也会产生不同的应用 当 时 电容电压 0 63E 当 时 电容电压 0 86E 当 时 电容电压 0
  • 通用嵌入式系统测试平台 ETest简介

    通用嵌入式系统自动化测试平台 通用嵌入式系统测试平台 Embedded System Interface Test Studio 简称 ETest 是针对嵌入式系统进行实时 闭环 非侵入式测试的自动化测试平台 适用于嵌入式系统在设计 仿真
  • 《阵列信号处理及MATLAB实现》绪论、矩阵代数相关内容总结笔记

    第一章 绪论 1 1 研究背景 1 1 1 阵列信号处理简介 将一组传感器按照一定方式布置在空间的不同位置 形成传感器阵列 用传感器阵列来接收空间信号 相当于对空间分布的场信号采样 得到信号源的空间离散观测数据 通过对阵列接受的信号进行处理
  • Lex和Yacc应用方法(一).初识Lex

    Lex和Yacc应用方法 一 初识Lex 草木瓜 20070301 Lex Lexical Analyzar 词法分析生成器 Yacc Yet Another Compiler Compiler编译器代码生成器 是Unix下十分重要的词法分
  • Feign的使用

    基于Feign远程调用 Feign说明 Feign是一个声明式的http客户端 其作用是帮助我们优雅的实现http请求的发送 官网地址 https github com OpenFeign feign Feign的使用 修改服务的pom x
  • MVC中的项目案例

    我们先一起来看看超期的效果图吧 以上就是超期的效果图 我来解析一下 超期操作的模态窗体弹出的条件与归还一样 应选择需要超期的书籍 再弹出模态窗体 模态窗体弹出 数据自动回填上去 罚款金额 超期天数 0 2 获取当前时间为罚款时间 罚款成功后
  • 解决python3在import cv2时报错问题

    在安装了ros 在import cv2时会报错 如下 import cv2 ImportError opt ros kinetic lib python2 7 dist packages cv2 so undefined symbol Py
  • CMake(七):函数和宏

    回顾到目前为止涉及的材料 CMake的语法已经开始看起来很像一门编程语言 它支持变量 if then else逻辑 循环和包含要处理的其他文件 毫无疑问 CMake还支持常用的函数和宏编程概念 就像它们在其他编程语言中的角色一样 函数和宏是
  • vistual studio 2017中导入pthread.h的配置方法

    1 下载pthread h的相关库文件 下载路径 https www mirrorservice org sites sourceware org pub pthreads win32 pthreads w32 2 9 1 release
  • 从技术小白到编程大神的技术书籍推荐

    本人算不上大神 也非计算机专业出身 本着一股热爱技术的精神 研究过各种计算机技术 对于知识的索取方式 比较习惯看书 当然 随着认识的加深 以及新技术的层出不穷 也常接触各种技术文档 早些时候阅读过很多不错的计算机书籍 对于计算机底层的深入认
  • spring boot 提示:程序包不存在,解决方法总结

    背景 之前出现过这样的问题 打包安装父项目就好了 今天改了一下代码 重新编译的时候 又出现了这样的情况 决定深度挖掘一下这里面的问题 spring boot 提示 程序包不存在 解决方法总结 spring boot 提示 程序包不存在 解决
  • Mysql系列(四)彻底理解MVCC+行锁+表锁+间隙锁

    文章目录 一 什么是MVCC 二 什么是行锁 表锁 间隙锁 三 MVCC与各种锁的关系 四 MVCC的实现原理 4 1 多版本 4 2 undo log 4 2 readview 一 什么是MVCC MVCC Multi Version C