MySQL MVCC详解

2023-11-20

为什么需要MVCC

在没有MVCC之前,是使用读写锁(共享锁/排它锁)来进行并发控制的,读锁和读锁之间不互斥,写锁和读锁互斥,写锁和写锁互斥。
但是频繁加锁会导致数据库性能低下,这时出现了一种不加锁来解决读写冲突的方法,它会让数据库维护每条数据的多个版本,让不同的事务看到特定版本的数据,这个方法就是MVCC。

什么是MVCC

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种用来解决读写冲突的无锁并发控制的方法,可以提高数据库并发读写的性能。

什么是快照读和当前读

快照读

不加锁的select操作是快照读,快照读读到的数据可能是之前的历史版本。快照读的实现是基于MVCC。

当前读

像select lock in share mode(共享锁),select for update,update,insert,delete(排它锁)这些操作都是当前读,它读取的是记录的最新版本,读取时会对这些记录加锁,保证其他并发事务不能修改这些记录。

MVCC的实现原理

MVCC是通过隐式字段,undo log和read view来实现的。

隐式字段

InnoDB在表中每行记录的后面,都隐式记录了几个隐藏的字段:

  1. DB_ROW_ID:自增ID,如果数据表没有主键,InnoDB会以DB_ROW_ID来生成聚簇索引
  2. DB_TRX_ID:最近插入/修改事务ID,记录创建该记录/最后一次修改该记录的事务ID
  3. DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本
    在这里插入图片描述

Undo Log

undo log就是为了实现回滚操作而记录的日志。undo log分为两种,分别为:

  1. insert undo log:在插入数据时产生,会记录这条数据的主键值,回滚时会将这个主键值对应的记录删掉。只在事务回滚时需要,所以在事务提交后会被立即丢弃。
  2. update undo log:在更新或删除时产生,会把修改这条记录前的旧值都记录下来,回滚时会将这个记录更新为旧值。不仅在事务回滚时需要,在快照读时也需要,所以不能随便删除;只有当日志不再会被用到时,才会被purge线程清除。

在MVCC中用到的是update undo log,它的结构如下:
在这里插入图片描述

Read View

read view就是事务进行快照读操作的时候生成的读视图(并不是每次快照读都会生成),read view主要包含以下四个属性:

  1. trx_list:活跃的事务ID列表;
  2. creator_trx_id:当前事务ID;
  3. up_limit_id:记录trx_list中最小的事务ID;
  4. low_limit_id:尚未分配的下一个事务ID。

当读取一条数据时,会先将这条数据的最新记录的DB_TRX_ID取出来,和read view中的属性进行可用性判断,如果不符合可见性的话,那就会通过DB_ROLL_PTR去undo log中取出上一个版本记录中的事务ID再进行可见性判断,以此类推,直到找到可见的记录为止。

可见性判断是使用可见性算法实现的,具体判断过程如下:

  1. 如果 DB_TRX_ID < up_limit_id 或 DB_TRX_ID == creator_trx_id,则该记录可见;
  2. 如果 DB_TRX_ID >= low_limit_id,则该记录不可见;
  3. 判断DB_TRX_ID是否在trx_list中;如果在,说明生成read view的时候,修改这个记录的事务还没提交,所以该记录不可见;如果不在trx_list中,说明生成read view之前修改这个记录的事务已经提交了,所以该记录可见。

事务隔离级别与MVCC的关系

READ UNCOMMITTED(读未提交)

READ UNCOMMITTED级别直接读取数据的最新记录,因此不会使用MVCC。

READ COMMITTED(读已提交)

READ COMMITTED级别会使用MVCC,在每次进行快照读都会生成新的read view,所以每次读取到的都是已提交的最新版本的记录,这样就可以解决脏读问题。

REPEATABLE READ(可重复读)

REPEATABLE READ级别会使用MVCC,只有在第一次进行快照读会生成read view,之后的快照读都会沿用第一次生成的read view,所以每次快照读读到的数据都是一样的,这样就可以解决脏读问题以及快照读的不可重复读、幻读问题。
RR级别下当前读的不可重复读和幻读问题
在快照读和当前读同时使用时,仍然有可能发生不可重复读和幻读的问题,需要使用next-key lock或行锁来解决。详细内容可以查看另一篇文章:MySQL RR级别下仍然会发生幻读和不可重复读

SERIALIZABLE(串行化)

SERIALIZABLE级别是通过加锁来访问数据,因此不会使用MVCC。

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

MySQL MVCC详解 的相关文章

  • 如何在 Node.js 中使用 Winston 将日志存储到 mysql 数据库

    我正在使用 winston 为我的应用程序进行日志记录 我已经使用这个完成了文件传输 class LoggerHelper extends BaseHelper constructor cApp super cApp this props
  • mysql 使用什么样的哈希?

    我正在编写类似于 phpMyAdmin 的自己的代码 但我需要用户能够使用 mysql 数据库中的用户名和密码登录 我需要知道mysql数据库使用什么样的哈希来存储每个用户的密码 我检查了 dev mysql com 寻找答案 但除了以 开
  • pyodbc 无法正确处理 unicode 数据

    我确实使用 pyodbc 成功连接了 MySQL 数据库 并且它可以很好地处理 ascii 编码的数据 但是当我打印使用 unicode utf8 编码的数据时 它引发了错误 UnicodeEncodeError ascii codec c
  • mysql 中 INSERT 语句的计算列

    假设我想要一个表来记录其他表中的日期和列数 或者任何类型的数学 字符串连接等 CREATE TABLE log id INTEGER NOT NULL AUTO INCREMENT date DATETIME NOT NULL count
  • 日常 MySQL(部分和过滤)复制的最佳实践?

    我有一个相当大的数据库 有超过 40 个表 我只需要复制几个表 5 并且每个表也被过滤 我正在寻找一些复制这些数据的最佳实践 每天就足够了 我可以只选择几个表并为每个表包含一些 WHERE 子句 我正在考虑为每个表启动 mysqldump
  • 通过 PDO 将双精度数插入 MySQL 时精度损失

    我遇到了这种非常烦人的行为 我想知道我是否做错了什么 或者这是否是故意的 如果是的话 为什么 每当我在 php 5 3 中有一个 double 类型的变量 并且想将其插入到数据库 MYSQL 5 0 的 double 类型字段中时 该值总是
  • 重用 PDO 语句 var 会使进程崩溃

    我重用一个变量来存储两个不同的 PDO mysql 语句 stmt dbh gt prepare SELECT stmt gt execute stmt dbh gt prepare UPDATE crash here Error in o
  • Chart.js - 使用 mysql 和 php 从数据库获取数据

    我正在尝试将静态数据转换为使用数据库结果 我将使用MySQL and PHP 示例代码 var randomScalingFactor function return Math round Math random 100 var lineC
  • 如何在 MySQL 中启用严格 sql_mode?

    我怎样才能启用严格sql mode在 MySQL 中 我想从 SQL 中获取数据并在中处理相同的数据strict mode 我现在的sql mode is mysql gt SELECT sql mode sql mode NO ENGIN
  • MySQL - 从另一个表插入与常量合并的数据

    我有一个包含一些数据的临时表 products temp 并且我有另一个需要将数据插入其中的表 产品 我需要在新记录上手动设置一些常量 例如vendor id 1等 是否可以在一次请求中插入临时表数据和常量 临时产品 product nam
  • 如何绑定值 INSERT INTO mysql perl

    我有下面的代码可以工作 但我需要知道如何绑定它们以确保安全 如果我只是将 new row 替换为 并将其放入执行中我收到错误 感谢您的帮助 foreach my field account field order new row param
  • 使用多个 WHERE 子句更新 Codeigniter 中的批次

    我查看了 CI 用户指南来了解如何处理update batch 并且它似乎只接受一个索引来匹配要更新的行 但在我的例子中 我需要指定两个索引 例如lang and id page我一起用作索引 这样的lang en id page 115是
  • Unicode(希腊语)字符存储在数据库中,例如“??????”

    数据库中的希腊字符就像问号 我找不到解决办法 我使用 Java Swing 开发了一个应用程序 但是当我在 MySQL 中插入希腊字母时 就像问号一样 我将数据库排序规则更改为 utf8 并将列也更改为 utf8 我的项目编码设置为UTF
  • 从两个表中搜索然后删除

    我有两个包含成员数据的表 与 member id 列链接 我需要搜索所有记录email列以 pl 结尾 然后 我需要为此删除两个表中的所有记录 基于 member id 是否可以通过一条 SQL 语句完成此操作 SELECT member
  • 使用 Ruby on Rails 索引多列

    我在 Mysql 数据库中有一个表 我想在其上使用多列索引 如何在不使用 mysql 控制台的情况下在 Rails 中执行此操作 在迁移定义中 您可以这样做 add index table name column1 column2
  • 纠正mysql创建用户时语法错误

    所以我很常见ERROR 1045 28000 Access denied for user root localhost using password YES mysql错误 我已经尝试了论坛上的所有典型修复 通过 mysql safe 方
  • 如何为 MySQL 和 Postgres 编写不区分大小写的查询?

    我在本地运行 MySQL 数据库进行开发 但部署到使用 Postgres 的 Heroku Heroku 处理几乎所有事情 但我不区分大小写的 Like 语句变得区分大小写 我可以使用 iLike 语句 但我的本地 MySQL 数据库无法处
  • 在 ASP.NET MVC 中使用 MySQL 的 AccountController

    在 Visual Studio 中创建默认的 ASP NET MVC 项目会设置一个可以在其中注册用户的基本项目 我将如何继续更改它以使用 MySQL 服务器而不是 SQLServer 现在可以使用了 安装最新的 Connector NET
  • 不唯一的表/别名

    因此 我尝试使用多个联接来运行此查询 以获得我想要的精确行 但我不断收到此错误 不唯一的表 别名 ss prices 我正在运行的查询 select ss accounts id ss accounts bot acc id ss acco
  • ASP.NET API:尚未为此 DbContext 配置数据库提供程序

    我正在尝试从我的 Net Core API 项目连接到 MySql 数据库 这是我的上下文类 public class MyContext DbContext public MyContext public MyContext DbCont

随机推荐

  • Linux alien命令

    一 简介 alien是一个用于在各种不同的Linux包格式相互转换的工具 其最常见的用法是将 rpm转换成 deb 或者反过来 二 安装 http toutiao com a6188997768449360129 三 实例 http www
  • sqlmap参数详解

    命令及详解 h 帮助 version 版本号 d 连接数据库 mysql root root 192 168 3 20 3306 db 数据库种类 账号 密码 地址 端口 库 current db 当前数据库 dbs 列出所有数据库 等于s
  • 软件测试是干什么的 1分钟带你快速了解清楚软测的工作性质

    近几年 国内软件测试行业迅猛发展 不少行外人都能经常听到某某软件测试岗位在高薪招聘消息 等 所以很多不了解情况的人就想要问了 软件测试到底是干什么的 什么样的人才能够当软件测试员 关于大家关心这两个问题 小编特做了如下回答 软件测试是干什么
  • Selenium RemoteWebDriver使用—让你的代码与测试分离(远程测试)

    目录 一 写在前面 二 RemoteWebDriver基本使用 2 1 配置环境 2 2 配置环境命令 2 3 代码示例 三 扩展使用 3 1 浏览器版本和平台参数 3 2 浏览器启动相关参数 一 写在前面 在学习Selenium基础的时候
  • 【实践篇】领域驱动设计:DDD工程参考架构

    背景 为什么要制定参考工程架构 不同团队落地DDD所采取的应用架构风格可能不同 并没有统一的 标准的DDD工程架构 有些团队可能遵循经典的DDD四层架构 或改进的DDD四层架构 有些团队可能综合考虑分层架构 整洁架构 六边形架构等多种架构风
  • Python 常用基础模块(四):sys模块

    目录 一 sys模块介绍 1 1 什么是 Python 解释器 说明 1 2 sys 模块的作用 二 常用方法及属性介绍 2 1 modules属性 将模块名称映射到已加载模块的字典 2 2 getdefaultencoding 方法 获取
  • YOGA 14s开机黑屏——试试提高亮度

    联想yoga 14s 开始动画是有的 但开机动画后就黑屏了 折腾了半天 按下亮度增大键后屏幕亮了 好像联想笔记本比较支持亮度最低即为0
  • 一周简报(项目尾声)

    XX海油项目已经进入尾声 大部分的工作都已经完成 目前我们所做的就是完善系统中的Bug 以及面对客户提出的某些部分的需求变更 由于形式所迫 我们的战斗由 城市 转入 农村 由 地上 转入 地下 由 阵地战 转为 游击战 我们当前的任务是以客
  • 通过源码包*.src.rpm定制开发rpm

    为什么80 的码农都做不了架构师 gt gt gt 1 基本流程 1 下载 安装相应的src rpm包 wget xxx src rpm rpm ivh xxx src rpm 这里的 安装 是指把xxx src rpm中的tar gz p
  • 活动报名

    活动议程 日期 5月5日 周五 时间 主题 14 30 14 35 开场简介 袁洋 清华大学交叉信息学院助理教授 青源会会员 14 35 15 20 环境不变最小二乘回归 方聪 北京大学智能学院助理教授 青源会会员 15 20 15 50
  • 计算机网络分组交换特点,分组交换技术在计算机网络技术中的作用及特点是什么?...

    分组交换是以分组为单位进行传输和交换的 它是一种存储 转发交换方式 即将到达交换机的分组先送到存储器暂时存储和处理 等到相应的输出电路有空闲时再送出 采用存储转发的分组交换技术 实质上是在计算机网络的通信过程中动态分配传输线路或信道带宽的一
  • Android中实现全屏、无标题栏的两种办法(另附Android系统自带样式的解释)

    在进行UI设计时 我们经常需要将屏幕设置成无标题栏或者全屏 要实现起来也非常简单 主要有两种方法 配置xml文件和编写代码设置 1 在xml文件中进行配置 在项目的清单文件AndroidManifest xml中 找到需要全屏或设置成无标题
  • c++ 二进制、八进制、十进制、十六进制相互转换

    itoa 和strtol 可以实现二进制 八进制 十进制 十六进制之间的相互转换 包含在 inculde lt cstdlib gt 1 十进制转换为其他进制 使用itoa int dec char str int R 将十进制数dec转换
  • python执行JavaScript代码

    1 简单使用 import execjs execjs eval new Date 返回值为 2018 04 04T12 53 17 759Z execjs eval Date now 返回值为 1522847001080 需要注意的是返回
  • selenium 获取属性值的两种方法

    初衷是因为要通过属性值判断是否按钮是否disabled 获取属性值的两种方法 1 通过js获取 class text dr execute script return arguments 0 getAttribute class TAG a
  • 关于“service iptables save“的“命令只支持LSB动作”的报错解决方法

    1 报错复现 service iptables save 报错如图 2 解决方式 2 1 先停止防火墙 systemctl stop firewalld 2 2 执行 yum install y iptables service 执行完毕后
  • 四路服务器销售排名,专注企业核心业务 新华三四路服务器2019上半年销售额占比持续增长...

    近日 IDC发布的 2019年第二季度中国x86服务器市场跟踪报告 显示 2019年上半年 紫光旗下新华三集团四路服务器在中国市场销售额排名第二 市场份额环比大幅增长 从中国市场销销售额数据来看 2018年下半年 新华三集团四路服务器市场销
  • QT实现多线程,以及子线程调用主线程方法与变量

    实现思路 第一步需要将子线程声明为主线程的友元类 第二步是将主线程类对象的地址通过信号槽传递给子线程中创建的对象 使得子线程能访问主线程的数据的 1 子线程 displayresult h 头文件 伪代码 include tabwindow
  • 算法学习——贪心算法之币种统计

    算法描述 币种统计 单位给每一位员工发工资 精确到元 为了保证不临时换零钱 使得每个员工取款的张数最少 在取工资前统计所有员工所需要的各种票面的张数 约定票种为100 50 20 10 5 2 1元 并验证币种统计是否正确 算法思路 算法描
  • MySQL MVCC详解

    为什么需要MVCC 在没有MVCC之前 是使用读写锁 共享锁 排它锁 来进行并发控制的 读锁和读锁之间不互斥 写锁和读锁互斥 写锁和写锁互斥 但是频繁加锁会导致数据库性能低下 这时出现了一种不加锁来解决读写冲突的方法 它会让数据库维护每条数