mysql mvcc机制详解

什么是当前读、快照读?

当前读

当前读指的是读取数据的​**​最新提交版本。**底层是通过对数据加锁加锁实现的

当前读sql语句有:

  • select lock in share mode
  • select for update
  • insert
  • update
  • delete

快照读

快照读指的是读取数据在某个时间点的​​快照(版本)​​,而不是数据的最新版本

快照读sql语句:普通selcet语句。底层是利用mvcc机制实现的


MVCC是什么?

mvcc就是多版本并发控制。多版本:指mysql维护着行数据的多个版本。

并发控制 :在多个事务同时操作某一行记录时,mysql控制返回多个版本的行记录中的某个版本

用来解决什么问题?

用来解决读写冲突问题。

数据库(普通select语句)并发事务时会出现脏读、不可重复读、幻读问题,也需要利用mvcc机制来解决。

流程:一条select语句来查询数据,但是查询的数据有多个版本,这时就要选择其中的某一个版本返回

数据隔离级别和并发问题

脏读 (Dirty Read)、不可重复读 (Non-Repeatable Read) 和 幻读 (Phantom Read)​​ 是数据库事务并发执行时,在没有采取足够隔离措施的情况下,会产生的三类典型问题。

mvcc机制实现了隔离级别,可以解决这三类并发问题

脏读

要解决脏读,就得上读已提交的隔离级别

得保证一个事务只能读取到其他事务已经提交的数据,没提交的就不该读取到

不可重复读

解决不可重复读问题,就得上读已提交隔离级别

一个事务第一次读取之后,后面读取得每一次数据都应该和第一次读取的一样

那就得维护一份数据的多个版本

每个事务修改一次就生成一个新版本,让不同事务读取不同的版本

在读已提交的得隔离级别下,让事务去读已经提交的数据版本,就可以避免脏读

在不可重复读的隔离级别下,让事务每次读到同一个版本的数据,这样每次读到的都是一样的了,就避免的不可重复读的问题

把修改的数据版本记录到undo log中,给表加一个隐藏字段,叫回滚指针

回滚指针指向undolog日志,日志记录了该表的修改记录的各个版本

利用回滚指针将历史版本串联成一个列表,想读哪个,查找即可

那一个事务来查数据,怎么知道要查哪个版本的数据呢?

所以要为每个事务分配一个id,事务id自增分配。通过对比事务id的大小,就知道哪个事务创建的早、哪个晚,记录哪些事务提交了,哪些未提交,让提交的早的事务不要看提交的比较晚的数据即可。所以要给表加上隐藏字段修改数据的事务id,谁修改了这条数据,就把对应的事务id记录下来

readview:4个重要字段:比较复杂,利用数轴来看

记住作用:就是决定在多个版本中,到底该读哪一个版本

undolog记录数据版本

readview去判断这个数据版本对当前事务的可见性

MVCC怎么实现的?

隐藏字段、undolog版本链、readview

undolog版本链、readview是怎么回事?

四种隔离级别怎么实现的

读未提交

不加任何读锁实现的。(假设:我现在在读这条数据,加了读锁,别人就不能修改。不加读锁,别人就可以修改我在读的数据)

读操作不加锁,就可以直接读取最新版本的数据,即使这些数据被其他事务用排他锁锁住(脏读)

会发生:脏读、不可重复读、幻读

读已提交

可以基于锁实现也可以基于mvcc实现(mvcc更常见)

mvcc的实现原理:

每个​​语句​​开始时都会生成一个新的快照(读视图readview)。

一个 Read View主要包含以下核心内容:

  1. m_ids: 一个列表,记录了在本 Read View创建时,系统中所有​​活跃的(尚未提交的)事务​​的事务 ID
  2. min_trx_id: 记录 m_ids列表中最小的那个事务 ID。
  3. max_trx_id: 记录在本 Read View创建时,系统已经分配的下一个事务 ID(即当前最大事务 ID + 1)。
  4. creator_trx_id: 创建这个 Read View的事务自己的 ID(只有该事务自己有写操作时,这个值才不为空)。

每次查询看到的都是这个​​语句级快照​​的最新已提交数据。所以在一个事务内,两次相同的查询可能会看到不同的数据(不可重复读,在'读已提交'隔离级别下,两次查询分别生成了两个不同的 Read View)。

判断某一事务对于当前创建快照的事务是否可见的规则

可重复读

mvcc的实现原理:

在​​事务开始​​时生成一个一致性快照,而不是语句开始。

整个事务期间,所有​​普通​​的 SELECT查询都基于这个​​事务级快照​​。因此,无论查询多少次,看到的数据都是一致的。这样就不会生成多个快照。

串行化

读未提交怎么实现?

不用管

串行化:加锁

可重复读怎么实现?(复用readview和mvcc机制)

可重复读会在第一次select时生成一个readview,通过readview判断应该读哪个数据

读已提交怎么实现?

每次select时就会生成一个新的readview

相关推荐
IBMS楼宇自控40 分钟前
IBMS-建筑内分散的子系统(如 BA、安防、消防、能源、电梯等)进行数据互联、功能协同与智能管控
大数据·数据库·人工智能
GBASE1 小时前
GBASE南大通用技术分享:GBase 8c 数据库分区表实践探秘(一)
数据库
跑跑快跑1 小时前
Macbook安装MySQL报错
数据库·mysql
GBASE1 小时前
GBASE南大通用技术分享:GBase 8c 数据库分区表实践探秘(二)
数据库
开开心心就好2 小时前
文档格式转换软件 一键Word转PDF
开发语言·前端·数据库·pdf·c#·word
Elastic 中国社区官方博客2 小时前
将 agents 连接到 Elasticsearch 使用模型上下文协议 - docker
大数据·数据库·人工智能·elasticsearch·搜索引擎·docker·ai
叫我阿柒啊3 小时前
Java全栈工程师的实战面试:从基础到微服务的全面解析
java·数据库·vue.js·spring boot·微服务·前端开发·全栈开发
oioihoii3 小时前
深入浅出:贴片式eMMC存储与国产芯(君正/瑞芯微)的协同设计指南
数据库·sd卡·sd nand·嵌入式tf卡·存储芯片
拾忆,想起3 小时前
Redis发布订阅:实时消息系统的极简解决方案
java·开发语言·数据库·redis·后端·缓存·性能优化