当前位置: 首页 > news >正文

深入浅出MySQL事务实现底层原理

重要概念

事务的ACID

  • 原子性(Atomicity):即不可分割性,事务中的操作要么全不做,要么全做
  • 一致性(Consistency):一个事务在执行前后,数据库都必须处于正确的状态,满足完整性约束
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行
  • 持久性(Durability):事务处理完成后,对数据的修改就是永久的,即便系统故障也不会丢失

脏读、幻读、不可重复读

  • 脏读,读取了未提交的数据
  • 不可重复读,事务A期间读取多次b,b被其他事务影响,导致值不可重复
  • 幻读,幻读和不可重复读有点像,它是事务A期间统计多次同一批数据,统计结果不一样。原因是被其他事务影响。它们的区别主要在于前者读取精确的某几条数据,后者则是范围统计——多版本不好控制

主从复制的原理

  • 主数据库有个bin log记录了所有sql语句
  • 把主数据库的bin log的语句复制到从数据库
  • 从数据库在relay log重做日志中再执行一遍这些sql

具体而言,
在这里插入图片描述

  • 主数据库启用输出线程,输出bin log
  • 从数据库IO线程,负责从主数据库里拉取bin log,写入到relay log
  • sql线程,将relay log重做

三大日志

bin log、redo log和undo log

bin log是归档日志,用于主从复制、数据备份等。
redo log是重做日志,用于实现事务持久性。在事务在提交时断电重启后,可以正常从中恢复。
undo log为回滚日志,用于实现事务的原子性,即当事务失败时,可以全部操作都取消。

bin log和undo log都是MySQL里边服务层的概念,它记录的是逻辑记录,例如完成了什么SQL。而redo log是存储层的物理操作日志,例如“在某个数据页上做了更改”。
在执行更新语句过程,会记录 redo log 与 binlog 两块日志,以基本的事务为单位,redo log 在事务执行过程中可以不断写入,而 binlog 只有在提交事务时才写入,所以 redo log 与 binlog 的写入时机不一样。

buffer与同步

既然是日志,那就躲不开缓存和落盘策略,这当然也是很通用的一些解决实践。这里以redo log为例:
在这里插入图片描述

落盘时机,可以通过配置来指定:

  • 0,事务提交不落盘,根据异步同步线程的时间来定(通常是1s)
  • 1,每次事务提交都落盘
  • 2,写入pagecache,介于0和1之间

日志提交的事务

在进行数据库操作的时候,需要同时操作多个日志,这个时候如何保证事务性呢?例如,宕机之后,如何确保binlog和redo log的数据是一致的?
这和[[分布式事务]]做的事情基本是一样的。MySql中采用两阶段进行日志的事务提交。
在这里插入图片描述

将redo log拆成两个阶段,最终提交阶段在binlog完成之后再提交。故障恢复的时候,不管在什么阶段,一切认准binlog的提交记录。即使在redolog commit期间出错,那么只要binlog落库成功,说明redolog一定parepare完成,可以恢复提交。

这又侧面印证了一个想法:分布式事务,其实本质上是把一件很大的、多阶段的过程,拆解,细分,尽可能把最终这个影响数据一致的过程缩小到最小粒度,尽管无法完全消除,尽可能减少出错的可能性。例如上述例子,就是把耗时的redolog写入过程拆出去,缩小到最终redo log的提交这个更短、更细粒度的过程上。

MVCC如何实现

copy on write

MVCC其实体现的是copy on write的一种思想——追求数据不变性,那么就直接复制一份快照。
数据库这么大的数据量,当然不可能是真的复制一整个库、一整个表,只需要复制相应的行就可以了。那么MySQL到底是怎么实现的呢?
这是必然是一个非常复杂的机制,涉及到并发SQL复杂操作、多版本数据、各个事务之间实时的可见性管控。
核心的有两点:
数据库通过两个核心隐藏列来完成多版本记录:

  • DB_TRX_ID,当前事务ID。单调递增,因而可以通过大小确定当前事务和其他事务的可见性——对比事务ID大小即可。例如,事务ID小于它的就可见,大于它的就不可见。你可以理解,这个就是版本。
  • DB_ROLL_PTR。回滚指针,指向对应的redo log记录。上边记录了“版本号”,那么,我们就会好奇,copy on write中的精髓,copy又是怎么体现的呢?答案就是,通过回滚指针。它不会直接复制一行出来,而会在原行上边修改,如果需要找到上一个版本,就通过回滚指针找到redo log,从而找到上一个版本。

从插入和更新来分析实际分析一下:
insert,由于是新增数据,所以不需要redo log指针,只需要记录事务id。
在这里插入图片描述

update,更上边分析一样,除了记录事务ID还得记录回滚指针。
在这里插入图片描述

第二次修改,这里重点来了,多版本如何copy呢?答案是拉链:
在这里插入图片描述

可见性保证

事务之间可见性的如何保证,这个也是一大难题。
大致描述一下我的理解:MySQL在开启事务的时候,会收集当前活跃的事务列表,于是它就可以通过事务ID,加上上边的多版本数据,去分析当前存在的数据变更,自己可见的是哪些,不可见的是哪些。
下边是当前可视视图的声明。

class ReadView {
private:trx_id_t m_low_limit_id;      /* 目前出现最大的事务ID,大于等于这个 ID 的事务均不可见 */trx_id_t m_up_limit_id;       /* 小于这个 ID 的事务均可见 */trx_id_t m_creator_trx_id;    /* 创建该 Read View 的事务ID */trx_id_t m_low_limit_no;      /* 事务 Number, 小于该 Number 的 Undo Logs 均可以被 Purge */ids_t m_ids;                  /* 创建 Read View 时的活跃事务列表 */m_closed;                     /* 标记 Read View 是否 close */
}

处于最大、最小ID之间的,就是活跃但不可见的事务列表。
在这里插入图片描述

事务的实现

好了,这下我们有充足的知识可以来讨论如何实现事务了。

整体方案

  • 原子性,undo log,事务中断恢复
  • 持久性,redo log,同步写回磁盘,提交断电时可恢复
  • 隔离性,通过读写锁和MVCC来实现的
  • 一致性,通过上述三者来实现的。

隔离性,对应四种隔离级别

READ UNCOMMITTED

在这里插入图片描述

读不加锁,不排斥写。

  • 优点:读写并行,性能高
  • 缺点:造成脏读

READ COMITTED

在这里插入图片描述

读不加锁,读写分离。但这里MVCC的方式,是每次读的时候,都会读取不同版本,这会造成不可重复读问题。

当然,也有幻读问题。

REPEATABLE READ(Mysql默认隔离级别)

最简单的方式,读写锁实现,让读写串行:

在这里插入图片描述

  • 优点:实现起来简单
  • 缺点:无法做到读写并行

MVCC

在这里插入图片描述

通过版本控制,解决版本不同问题产生不可重复读的问题

  • 优点:读写并行
  • 缺点:实现的复杂度高,依然存在幻读的问题

InnoDB是可以解决幻读的,大致的思想也很简单, Next-key Lock对查询间隙进行加锁,不让插入自然也就不会有幻读问题。

SERIALIZABLE

在这里插入图片描述

注:
可线性化和可串行化,听起来很像,感觉也很像。其实不太一样,两者是分布式数据库中的一致性模型,但后者主要指事务中的一种隔离级别。
我的理解是,最大的区别在于,可线性化要求对于所有事件,都必须满足所有时刻的先后可见性。而可序列化仅需要保证多个并行的事务和某个事务序列结果一致即可。
这非常像Java中重排和happen-before的理念。

参考

  1. https://blog.csdn.net/weixin_36380516/article/details/107572412
  2. https://javaguide.cn/database/mysql/innodb-implementation-of-mvcc.html#readview

相关文章:

深入浅出MySQL事务实现底层原理

重要概念 事务的ACID 原子性(Atomicity):即不可分割性,事务中的操作要么全不做,要么全做一致性(Consistency):一个事务在执行前后,数据库都必须处于正确的状态&#xf…...

SVM兵王问题

1.流程 前面六个就是棋子的位置,draw就是逼和,后面的数字six就代表,白棋最少用六步就能将死对方。然后呢,可以看一下最后一个有几种情况: 2.交叉测试 leave one out: 留一个样本作测试集,其余…...

yolov5_obb

yolov5_obb: 旋转目标检测从数据制作到终端部署全流程教学...

NextJs 初级篇 - 安装 | 路由 | 中间件

NextJs 初级篇 - 安装 | 路由 | 中间件 一. NextJs 的安装二. 路由2.1 路由和页面的定义2.2 布局的定义和使用2.3 模板的定义和使用① 模板 VS 布局② 什么是 use client 2.4 路由跳转的方式2.5 动态路由2.6 路由处理程序① GET 请求的默认缓存机制② 控制缓存或者退出缓存的手…...

变分自动编码器(VAE)深入理解与总结

本文导航 0 引言1 起源1.1 自编码器的任务定义1.2 自编码器存在的问题1.3 VAE的核心思路 2 VAE的建模过程2.1 VAE的任务定义2.2 真实分布 ϕ \phi ϕ是什么,为什么要逼近这个分布的参数,如何做?2.3 “重参数化(Reparameterization…...

Leetcode 剑指 Offer II 079.子集

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个整数数组 nums ,数组中的元素 互不相同 。返…...

Linux基础命令常见问题解决方案

Linux 基础命令常见问题解决方案 在Linux的日常使用中,用户经常会遇到各种各样的问题。本文旨在提供一个关于Linux基础命令的常见问题及其解决方案的全面指南。我们将覆盖30种不同的错误场景,并给出具体的解决步骤和示例,帮助初学者快速定位…...

LINQ(五) ——使用LINQ进行匿名对象初始化

总目录 C# 语法总目录 上一篇:LINQ(四) ——使用LINQ进行对象类型初始化 LINQ 五 ——使用LINQ进行匿名对象初始化 6.2 匿名类型 6.2 匿名类型 可以不用声明定义一个对象,直接使用new,然后直接赋值即可 string[] names { "Tom",…...

1小时从0开始搭建自己的直播平台(详细步骤)

本文讲述了如何从0开始,利用腾讯云的平台,快速搭建一个直播平台的过程。 文章目录 效果图详细步骤准备工作第一步:添加域名并检验cname配置1.先填加一个推流域名2. 点击完下一步,得到一个cname地址3. 将cname地址,配置…...

Python打包篇-exe

文章目录 pyinstallerauto-py-to-exe pyinstaller 命令行工具,语法自行查看官方help pip install pyinstallerauto-py-to-exe 基于pyinstaller的一款GUI工具,会自行打包py文件中依赖的库 pip install auto-py-to-exe auto-py-to-exe.exe //运行即可...

游戏找不到d3dcompiler_43.dll怎么办,教你5种可靠的修复方法

在电脑使用过程中,我们经常会遇到一些错误提示,其中之一就是“找不到d3dcompiler43.dll”。这个问题通常出现在游戏或者图形处理软件中,它会导致程序无法正常运行。为了解决这个问题,我经过多次尝试和总结,找到了以下五…...

如何使用多种算法解决LeetCode第135题——分发糖果问题

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…...

泰拉瑞亚从零开始的开服教程

前言 本教程将讲诉使用Linux系统搭建泰拉瑞亚服务器(因为网上已经有很完善的windows开服教程了),使用的Linux发行版是Debian11,服务端使用的程序是TShock,游戏版本是1.4.4.9 所需要准备的 一台服务器(本教程使用的是…...

【云原生】K8s管理工具--Kubectl详解(一)

一、陈述式管理 1.1、陈述式资源管理方法 kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口kubectl 是官方的 CLI 命令行工具,用于与 apiserver 进行通信,将用户在命令行输入的命令,组织并转化为apiserver 能识…...

2024.5.26.python.exercise

# # 导入包 # from pyecharts.charts import Bar, Timeline # from pyecharts.options import LabelOpts, TitleOpts # from pyecharts.globals import ThemeType # # # 从文件中读取信息 # GDP_file open("1960-2019全球GDP数据.csv", "r", encoding&quo…...

代码随想录-Day20

654. 最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums…...

揭秘C++ String容器:字符串操作的艺术

目录 ​编辑 引言 一、初识std::string:构造与初始化 二、字符串的操纵艺术:拼接、查找与替换 三、访问与遍历:字符的细腻触感 四、大小与容量:动态调整的智慧 五、进阶功能:探索更多可能 结语 引言 在C标准库…...

【C++】牛客 ——DP36 abb

✨题目链接: DP36 abb ✨题目描述 leafee 最近爱上了 abb 型语句,比如“叠词词”、“恶心心” leafee 拿到了一个只含有小写字母的字符串,她想知道有多少个 "abb" 型的子序列? 定义: abb 型字符串满足以下…...

SpringBoot如何实现跨域?

定义一个配置类,实现WebMvcConfigurer接口,重写addCorsMappings方法 Configuration public class CorsConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allow…...

SW 草图偏移 先预选

因为有些不能用链全部选,可以先框选要偏移的,再点偏移命令...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...