mysql mvcc

mysql mvcc,第1张

MVCC (Multi Version Concurrency Control的简称),代表多版本并发控制,用于支持RC(读已提交)和RR(可重复读)隔离级别的实现。在一个支持MVCC的并发系统中, 我们需要支持两种读, 一个是快照读, 一个是当前读。

MVCC最大的 优势 :读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能。

事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其 内存拷贝 (可理解为缓存),再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。事务日志采用的是追加的方式,因此写日志的 *** 作是磁盘上一小块区域内的顺序I/O,而不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多。事务日志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志(Write-Ahead Logging),修改数据需要写两次磁盘。

如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。

MySQL Innodb中跟数据持久性、一致性有关的日志,有以下几种:

MVCC是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的删除时间。当然存储的并不是实际的时间值,而是系统版本号(system version number)。每开始一个新的事务, 系统版本号 都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

下面看一下在RR隔离级别下,MVCC具体是如何 *** 作的。

保存这两个额外系统版本号,使大多数读 *** 作都可以不用加锁。这样设计使得读数据 *** 作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

RC隔离级别下,其实整个过程几乎一样,只是每次select的时候,都会生成一个快照,即增加版本号。读已提交就是在一次事务中,可以查询到新提交的数据。

简介:

大家好,我是xp,我又诈尸了

mvcc ,想必大家都不陌生,每个Java程序员都或多或少的了解过,不过不知道大家都是怎么学习的,是不是简单的百度一下呢?下面,我来带大家装个13,调试 mvcc 。咳,不是源码哈,但有那味了。

开卷开卷。

首先介绍一下 mvcc 的字面意思,全称: Multiversion Concurrency Control,翻译下来就是多版本并发控制技术。

脏读、 不可重复读 、幻读的概念就不多啰嗦了,mvcc具体的含义也不多啰嗦了,可以自行百度。 mvcc 解决了脏读、 不可重复读、部分幻读 ,包含了3个重要成分:

undo log作用:

在数据修改的时候,不仅记录了 redo log,还记录了 undo log 。但是 不同于 redo log, undo log 是逻辑日志。简单理解成, delete的时候,undo log会出现一条insert,update的时候,undo log会出现一条旧数据, 用来事务失败之后的回滚。

3个隐式字段:

Read View:

好了,理论讲完了,让我们嗨起来。

嗨之前,有一个情况单独说一下:

可以看到,此时的trx_id非常大,这是因为此时是只读事务。对于只读事务, InnoDB 并不会分配 trx_id,只有发生dml才会分配。这样有2个好处:

当commit了之后,我们使用SHOW ENGINE INNODB STATUS查看:

可以看到,显示该事务并没有开始。

好,回到正轨,相信大家都知道, 视图可见性判断(不知道的先百度 mvcc ):

整体是这样的:

第一步我们以 38488 为开始值,把 name 更新成 111 ,并且 commit

第二步以 38490 把 name 更新成 222,333 ,但是不 commit

当 38490 第一次修改为 222 的时候,数据结构大致是这样的:

使用 SHOW ENGINE INNODB STATUS 侧面验证:

当 38490 第二次修改为 333 的时候,数据结构大致是这样的:

使用 SHOW ENGINE INNODB STATUS 侧面验证:

第三步以 38491 去查询,此时生成的 m_ids 应该是 [348490,38491]

使用 SHOW ENGINE INNODB STATUS 侧面验证:

此时 ReadView 的几个属性值为:

接下来我们来验证结论:

1:不用验证,当前事务修改的肯定自己可见

2: 38491查询id=1的记录,name为111

38488 <348490,所以111可见

3:不用验证,38492是下个事务的id,还没生成呢,当前事务,肯定看不见下个事务修改的值

4:我们先把38491commit,把id为20的name更新成111

然后再开一个事务38496:

此时查id为20,是可见的

m_ids:[348490,38496],因为38491已经commit了,所以m_ids没有。此时的38491在m_ids之间,但是在m_ids里面找不到,所以可见。

好了,愉快的装13结束了,兄弟们,下次见。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/8368224.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-15
下一篇 2023-04-15

发表评论

登录后才能评论

评论列表(0条)

保存