MVCC多版本并发控制

26 篇文章 0 订阅
MVCC是一种并发控制方法,用于数据库管理系统中处理并发访问。它在MySQL的InnoDB存储引擎中实现,以提高并发性能,允许非阻塞读操作。当前读会锁定读取的记录,而快照读则基于历史版本提供非阻塞读。MVCC通过隐式字段、回滚日志和ReadView来实现,解决了读写冲突和事务隔离问题。
摘要由CSDN通过智能技术生成

1. MVCC

MVCC,全称Multi-VersionConcurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

2. 当前读

读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

像select lock in share mode(共享锁),select for update;update;insert;delete(排他锁)等这些操作都是一种当前读。

3. 快照读(提高数据库的并发查询能力)

基于多版本,读到的不一定是数据的最新版本,可能读到的是之前的历史版本。
前提:是隔离级别不是串行级别,串行级别下的快照读会退化成当前读

比如 不加锁的select操作,即不加锁的非阻塞读。

为什么会有快照读?

基于并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但在很多情况下它避免了加锁操作,降低了开销。

4. 当前读、快照读、MVCC关系

MVCC多版本并发控制指的是维持一个数据的多个版本,使得读写操作没有冲突,快照读是MySQL为实现MVCC的一个非阻塞读功能,MVCC模块在MySQL中的具体实现是由三个隐式字段,undo日志、read view三个组件来实现的。

5. MVCC解决的问题

数据库并发场景有3种:

  • 读读:不存在任何问题,也不需要并发控制
  • 读写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读。
  • 写写:有线程安全问题,可能存在更新丢失问题

MVCC是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照,所以MVCC可以为数据库解决以下问题:

  1. 并发读写数据库时,可做到读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
  2. 解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题。

6. MVCC实现原理

mvcc的实现原理主要依赖于记录中的三个隐藏字段,undolog,read view来实现的。

隐藏字段

每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段。

DB_TRX_ID6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id
DB_ROLL_PTR7字节,回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个旧版本
DB_ROW_ID6字节,隐藏的主键,如果数据表没有主键,那么innoDB会自动生成一个6字节的row_id

undo log

undo log 被称之为回滚日志,表示在进行insert,delete,update操作时产生的方便回滚的日志。
当进行insert操作时候,产生的undo log只在事务回滚的时候需要,并且在事务提交之后可以被立刻丢弃。
当进行update和delete操作的时候,产生的undolog不仅在事务回滚的时候需要,在快照读的时候也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除(当数据发生更新和删除操作的时候都只是设置一下老记录的deleted_bit,并不是真正的将过时的记录删除,因为为了节省磁盘空间,innodb有专门的purge线程来清除deleted_bit为true的记录,如果某个记录的deleted_id为true,并且DB_TRX_ID相对于purge现成的tead view可见,那么这条记录一定是可以被清楚的)

举例看一下undo log生成的记录链
在这里插入图片描述
(下图DB_ROW_ID依然为1)
在这里插入图片描述
在这里插入图片描述
注: DB_ROW_ID始终为1不变,图片有错误。
在这里插入图片描述

Read View

Read View是事务进行快照读操作的时候产生的读视图,在该事务执行快照读的那一刻,会生成一个数据系统当前的快照,记录并维护的系统当前活跃事务的id,事务的id值是递增的。

(假设我执行某个事务对2版本进行了更新,对3版本也进行了更新,那么我怎么确定要的是2之后的版本还是3之后的版本)

其实ReadView 的最大作用是用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当作条件去判断当前事务能够看到哪个版本的数据,也有可能读取的是当前行记录的undolog中某个版本的数据
在这里插入图片描述
在这里插入图片描述

8. RC(读已提交)、RR(可重复读)级别下的InnoDB快照读有什么不同

在这里插入图片描述

举例子:

RR下:事务1开始前会生成read view,另一边事务2更新插入新数据提交后,这边事务1内查询结果仍然是1个,执行提交后再查才会返回2个。

RC下:事务1的Read view是执行当前sql语句查询时就生成了,此时会总是获取到最新的修改提交记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值