惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
GbyAI
GbyAI
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
小众软件
小众软件
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
J
Java Code Geeks
WordPress大学
WordPress大学
Microsoft Security Blog
Microsoft Security Blog
IT之家
IT之家
F
Fortinet All Blogs
博客园 - 【当耐特】
H
Hackread – Cybersecurity News, Data Breaches, AI and More
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
C
Cybersecurity and Infrastructure Security Agency CISA
L
LINUX DO - 热门话题
Spread Privacy
Spread Privacy
O
OpenAI News
V
V2EX
博客园 - 三生石上(FineUI控件)
AI
AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Jina AI
Jina AI
H
Help Net Security
L
LINUX DO - 最新话题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tenable Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Cisco Talos Blog
Cisco Talos Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
酷 壳 – CoolShell
酷 壳 – CoolShell
Hacker News: Ask HN
Hacker News: Ask HN
S
Security @ Cisco Blogs
S
Securelist
T
The Blog of Author Tim Ferriss
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
雷峰网
雷峰网
V2EX - 技术
V2EX - 技术

郑文峰的博客

使用dify对接飞书多维表格 使用n8n对接飞书多维表格 服务启动时出现 OOM 一次服务升级时pg表DDL执行超时失败 Go语言高效IO缓冲技术详解 Go语言延迟初始化(Lazy Initialization)最佳实践 Go语言字符串拼接性能对比与优化指南 Go语言结构体内存对齐完全指南 Go语言空结构体:零内存消耗的高效编程 Go语言堆栈分配与逃逸分析深度解析 Go语言原子操作完全指南 Go语言内存预分配完全指南 Go语言不可变数据共享:无锁并发编程实践 Go语言零拷贝技术完全指南 Go语言遍历性能深度解析:从原理到优化实践 Go语言Interface Boxing原理与性能优化指南 Go协程池深度解析:原理、实现与最佳实践 使用etcd分布式锁导致的协程泄露与死锁问题 基于pre-commit的Python代码规范落地实践 初识 MCP Server pulsar阻塞导致logstash无法接入日志 django-prometheus使用及源码分析 kube-proxy源码分析 kubernetes service如何通过iptables转发 tcp缓存引起的日志丢失 django-apschedule定时任务异常停止 理解calico容器网络通信方案原理 理解flannel的三种容器网络方案原理 理解Linux IPIP隧道 理解VXLAN网络 理解Linux TunTap设备 快速了解iptables kafka中listener和advertised.listeners的作用 django rest_framework 分页 django后端服务、logstash和flink接入VictoriaMetrics指标监控 python中import原理 docker容器单机网络 手动实现docker容器bridge网络模型 mysql之日志 使用java开发logstash的filter插件 使用python实现单例模式的三种方式 redis之缓存 redis之分片集群 redis之哨兵机制 redis之主从库同步 redis之持久化 redis之五种基本数据类型 go中如何处理error pod中将代码与运行环境分离 ddt源码分析 python装饰器的使用方法 读书笔记:如何阅读一本书 使用ddt实现unittest的参数化测试 使用kubeadm安装k8s 优化gin表单的错误提示信息 gin中validator模块的源码分析 go简单使用grpc python简单使用grpc k8s之PV、PVC和StorageClass k8s之StatefulSet k8s之DaemonSet k8s之Job和CronJob k8s之ConfigMap和Secret k8s之Service k8s之Pod k8s之Deployment 容器的本质 docker容器 python迭代器与生成器 python元编程 python垃圾回收机制 python上下文管理器 django rest_framework使用jwt django rest_framework异常处理 django rest_framework 自定义文档 django压缩文件下载 django rest_framework使用pytest单元测试 django restframework choice 自定义输出数据 django Filtering 使用 django viewset 和 Router 配合使用时报的错 django model的序列化 django中使用AbStractUser django.core.exceptions.ImproperlyConfigured Application labels aren't unique, duplicates users django 中 media配置 django 外键引用自身和on_delete参数 django 警告 while time zone support is active Flask使用flask_socketio实现websocket flask结合mongo tornado 文件上传 tornado 使用jwt完成用户异步认证 tornado 用户密码 bcrypt加密 tornado 结合wtforms使用表单操作 tornado finish和write区别 tornado 使用peewee-async 完成异步orm数据库操作 pyspark streaming简介 和 消费 kafka示例 使用hue创建ozzie的pyspark action workflow count的性能优化 django rest_framework Authentication django celery 结合使用 网站
mysql之MVCC原理
zhengwenfeng · 2023-01-02 · via 郑文峰的博客

# 什么是 MVCC?

MVCC 的全称是 Multi- Version (opens new window) Concurrency Control,也就是多版本并发控制,该机制是只有支持事务的 InnoDB 引擎下才存在的,用来实现提高数据库的并发性能,可以做到:读不加锁,读写不冲突。

那么它是如何实现的呢?

# MVCC 的实现原理

在 Innodb 的每一行数据中都会保存多个版本,每个版本都有对应的事务 ID。

在开启每一个事务时,都会生成当前事务的版本号,当在该事务中操作修改数据时,都会生成一个新的数据行,该数据行在提交之前对其他事务来说是不可见的,然后将版本号更新到数据行中,这样就保证了每个事务操作的数据都是互不影响的,也不存在锁的问题。

在读操作时,我们只去快照读,而不读取正在修改的数据,这是两个不同版本的数据,所以操作上不会发生冲突。

# ReadView

Read View 是来表示当前事务的可见性的,通过上面的 MVCC 原理知道所有的行数据都是有版本的,那么哪些版本的数据在当前事务是可见的,也就是可读到的,哪些是不可见的。

创建 Read View 时,会构造一个数组来保存当前事务启动瞬间启动了但是没有提交的事务 ID。

  • 如果小于最小值,则是已经提交的事务,是可见的
  • 如果大于最大值,则代表是将来启动的事务,不可见
  • 如果在数组列表中,表示还没提交的事务,不可见
  • 如果大于最小值,小于最大值,但不在数组中,表示是已经提交了的事务,可见

创建 Read View 的时机在不同的隔离级别是不同。

  • 在读未提交中,直接读取的是最新版本的数据
  • 在读已提交中,在每次读取数据前,就会生成一个 Read View,然后再读取可见版本的数据。
  • 在可重复读中,在每次开启事务的时候,就会生成 Read View,在提交之前都一直如此使用。
  • 在串行化中,是通过加锁的方式来访问数据。

# Undo 日志

每条记录更新时,都会同时记录一条回滚操作。记录上的最新值都可通过回滚操作得到前一个状态值

在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。系统会判断在没有事务需要用到回滚日志时,回滚日志会被删除

不建议使用长事务的原因是,在事务提交之前,回滚日志都需要保存,导致占用大量存储空间。

# 快照读和当前读

快照读,就是当进行查询时,是根据 Read View 的视图可见性来读取对应版本的数据。

有这么一个场景,当前是可重复读的隔离界别,开始事务的顺序分别是 A、B、C,事务 C 更新 K 之后,最新的版本 102,当事务 B,根据 Read View 是看不到 102 版本的数据,那么其更新只能在 90 版本上去+1,这样的结果肯定是不对的,因为不是在最新的结果上进行+1,所以这里需要用到 当前读,也就是去读取当前数据的最新版本的数据,然后再进行+1。该当前读会对该行数据进行加锁,在该事务 commit 之前,其他事务都不能对其进行操作。

# 相关链接

  • https://blog.csdn.net/SIESTA030/article/details/123113437
  • https://blog.csdn.net/huaishu/article/details/89924250