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

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
Google DeepMind News
Google DeepMind News
博客园 - 司徒正美
Y
Y Combinator Blog
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
T
Tailwind CSS Blog
G
Google Developers Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
D
DataBreaches.Net
T
The Blog of Author Tim Ferriss
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
MyScale Blog
MyScale Blog
N
Netflix TechBlog - Medium
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
P
Proofpoint News Feed
Jina AI
Jina AI
B
Blog RSS Feed
腾讯CDC
阮一峰的网络日志
阮一峰的网络日志
D
Docker

郑文峰的博客

使用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网络
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