MVCC多版本并发控制的理解

前置知识

当前读与快照读

当前读
什么是当前读:读取的是 最新的数据,不会读到老数据。
何时触发:update、insert、delete、select lock in share mode、select for update时,总是当前读。
快照读
什么是快照读:读取的是 历史版本,不是最新的数据。
何时触发:select

MVCC多版本并发控制的理解
这些关系一定要搞清楚!

事务的ACID

原子性:事务要么全部成功,要么全部失败。实现:undolog回滚日志实现。相当于存储在磁盘中的历史记录链、还有一个更官方的名字: 快照
一致性:一致性是由其他三个实现的。

[En]

Consistency: consistency is achieved by the other three.

隔离:当事务并发执行时,内部操作不能相互干扰。实现:锁定实现。

[En]

Isolation: internal operations cannot interfere with each other when transactions are executed concurrently. Implementation: lock implementation.

持久性:事务一旦提交,对数据库的影响应该是永久的。实现:redolog实现。

Innodb引擎的日志

1、undolog
作用:保存历史快照。
目的:实现原子性,在MVCC中也起到了一定的作用。
2、redolog
作用:预写日志。
目的:为了高效实现持久性,将数据持久化。
详解:首先,在执行数据更新时,效率是低的,目前几乎所有软件硬件的瓶颈,都卡在了IO层面。IO有两种: 顺序读写随机读写。那明明是解释redolog的,怎么就说起了IO呢?这要先明确一点,就是顺序读写与随机读写的效率是谁快谁慢的问题。顺序读写:顾名思义,就是顺序向尾部一次添加数据,属于append的操作,不需要查找。随机读写:需要指针的移动查找。所以很明显,顺序读写的效率是要远高于随机读写的。举个例子,比如在一家饭店,中午有人来吃饭,这家店允许赊账,所以很多人会选择赊账,而店主呢,就把所有的赊账信息记录在一本厚厚的本子里,假设里面记了一万条赊账信息。好了,中午最繁忙的时候,所有员工都在忙着工作,如果有人要赊账,怎么办?根本没机会一个一个仔细找记录。所以很自然的就会想到,我在墙上装个黑板,或者单独在一张纸上列出来今天的赊账名单。等不忙了,我再慢慢地把名单记录到本子里。所以,现在已经很明显了,redolog就是顺序读写,它快速记录数据,然后数据再由顺序读写区域慢慢向随机读写区域转换。这就是 WAL:预写日志
redolog是Innodb引擎的日志,而MySQLserver中自带的日志中有binlog,所以它俩是共存的,所以在运行时,必须保证一致性,因为binlog是MySQL主从复制时向从机同步信息的,如果不写binlog,那么从机会出问题,但是应该先写哪一个呢?先写哪个都会出问题!一旦写第一个时断电,就会造成主机与从机不一致。解决的方法是给redolog加个状态,当redolog写完数据后,给它状态为prepare,然后去写binlog,当binlog写完后,再把redolog的状态从prepare改为commit。这就是 两阶段提交

MVCC

宏观来看,MVCC就是解决事务的隔离性的问题的。

MySQL的并发场景

MySQL的并发场景有三种: 读读读写写写
阅读:不存在数据安全问题。

[En]

Read: there is no data security problem.

读写:存在数据安全问题。比如肮脏的阅读、不重复的阅读、幻影阅读。

[En]

Read and write: there is a data security problem. Such as dirty reading, unrepeatable reading, phantom reading.

写道:存在数据安全问题。例如丢失更新。

[En]

Write: there is a data security problem. Such as missing updates.

而MVCC则是以 不加锁的方式解决读写冲突问题。

MVCC的组成部分

表的隐藏字段:数据库表在定义时除了自己声明的字段,还会包括一些隐藏字段,包括有:
DB_TRX_ID :最近修改事务ID。指创建这条记录或最后一次修改这条记录的事务id。
DB_ROLL_PTR :回滚指针。指向记录的上一个版本,即指向undolog首条记录。
DB_ROW_ID :隐藏主键。如果表没有主键,自动生成一个6字节的row id。

MVCC多版本并发控制的理解

readview

快照读时会产生readview,即select时会产生readview。

MVCC多版本并发控制的理解
举个demo:
MVCC多版本并发控制的理解
当select时,产生了快照读,此时生成的readview可以看到。
而如何看能否读取到值呢?MySQL有可见性算法。
MVCC多版本并发控制的理解
再举一个demo
MVCC多版本并发控制的理解
对比一下,如果按照我们的判断,可以发现蓝色的readview与第一个demo中的readview一模一样。但是问题在于,蓝色的select是不能读取到修改之后的数据的。这当然是因为蓝色的readview是错误的,它真正的readview其实就是黄色的readview,也就是下图
MVCC多版本并发控制的理解

结论

所以,隔离级别解决数据不可重复读的关键,在于MVCC生成readview的机制或者时机,如果是读已提交级别RC,每次快照读都会生成readview,所以会产生不可重复读的问题。如果是可重复读隔离级别RR,只会在第一次快照读时产生readview,不会有不可重复读的问题。
至此,MVCC结束
至于幽灵阅读的问题,需要锁定。影子阅读的根本原因是当前阅读和快照阅读一起使用!如果事务中只有快照读取,则永远不会出现幻影读取的问题。

[En]

As for the problem of phantom reading, it needs to be locked. The root cause of phantom reading is that current reading and snapshot reading are used together! If there is only snapshot reading in a transaction, the problem of phantom reading will never occur.

Original: https://www.cnblogs.com/coderhzy/p/16540440.html
Author: hzycoder
Title: MVCC多版本并发控制的理解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/505099/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球