京东面试:MySQL MVCC是如何实现的?如何通过MVCC实现读已提交、可重复读隔离级别的?

尼恩说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:

1.请解释什么是MVCC,它在数据库中的作用是什么?
2.在MySQL中,MVCC是如何实现的?请简述其工作原理。
3.MVCC是如何解决读-写和写-写冲突的?
4.在并发环境中,当多个事务同时读取同一行数据时,MVCC是如何保证每个事务看到的数据版本是一致的?
5.MVCC如何帮助提高数据库的并发性能?

最近有小伙伴在面试京东,又遇到了相关的面试题。小伙伴懵了,因为没有遇到过,所以支支吾吾的说了几句,面试官不满意,面试挂了。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V171版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,回复:领电子书

本文目录

● 尼恩说在前面
● 本文目录
什么是MVCC
● MVCC的根本目标:提升并发能力
● 提升并发的思想:COW思想
● Java中的CopyOnWriteArrayList
● 为啥MVCC要使用COW思想 呢?借鸡生蛋
● MVCC与锁的关系
MySQL事务隔离级别与MVCC
● 什么是事务
● 事务的ACID特性
● 4种 事务隔离级别
● 隔离级别、并发性、数据一致性的三角之间关系
并发事务的四种场景和MVCC的作用
● 读●读场景:
● 写●写场景
● 读●写、写●读场景
● 各并发事务场景的解决方案
MVCC的实现原理分析
组件1: InnoDB表的隐藏字段
● 隐藏的主键:row_id
● 隐藏的删除标识:deleted_bit
● 隐藏的最近更新事务ID:trx_id (DB_TRX_ID)
● 隐藏的回滚指针:roll_ptr
组件2:InnoDB引擎的Undo-log日志
● Undo-log有什么用途呢?
● Undo-log日志 版本链
● 为什么Undo-log日志要设计出版本链呢?
组件3:MVCC核心ReadView
● 什么是ReadView呢?
● ReadView的核心属性
● ReadView的读取规则
● ReadView的生成规则
MVCC实现原理
● MVCC实现原理 总结
● 注意:RC/RR 适用MVCC
MVCC 演示过程
● 快照读和当前读
面试官追问:MySQL 如何通过MVCC实现 读已提交 隔离级别的?
● 1. MVCC的基本概念
● 2. Read View的作用
● 3. 数据版本的可见性
● 5. 读已提交 隔离级别总结
面试官再追问:MySQL 又是如何通过MVCC实现 可重复读(REPEATABLE READ) 隔 离级别的?
● 1. 一致性视图(Read View)的创建
● 2. 解决脏读和不可重复读
● 3. 快照读与当前读
● 5. 如何避免幻读
● 问题 总结
面试官再追问:READ COMMITTED和REPEATABLE READ的区别是什么?
● 1. 核心区别:Read View的创建时机
● 2. 数据一致性表现
● 3. 幻读问题
● 4. 性能和并发性
● 5. 答案总结
面试官再追问:READ COMMITTED的缺点是什么?
● 1. 数据一致性较弱
● 2. 对业务逻辑的潜在影响
● 5. 适用场景的局限性
面试官再追问:MySQL默认的隔离级别为什么是REPEATABLE READ?REPEATABLE READ 的缺点是什么
● 1. MySQL默认隔离级别为 REPEATABLE READ 的原因
● 2. REPEATABLE READ的缺点
● 3 答案总结
面试官再追问:大厂的MySQL,为啥一般调整为的READ COMMITTED 隔离级别?
● 1. 提升并发性能
● 2. 减少死锁
● 3. 适应高并发场景
● 4. 兼容性和性能优化
● 5. 互联网业务 一般允许幻读
● 6 答案总结
面试官再追问:可重复读 什么时候使用了邻键锁 / 间隙锁(Gap Lock)和Next●Key Lock?
● 1. 范围查询时 使用邻键锁 :
● 2. 插入操作引发时 使用邻键锁 :
● 3. 唯一索引冲突检测时 使用邻键锁 :
面试官再追问:如何选择隔离级别?
● 1. 数据一致性要求
● 2. 读写 操作要求
● 3. 锁开销和 性能表现
● 4. 数据一致性问题
● 4. 默认隔离级别与调整
● 5. 实际业务参考案例
● 答案总结

什么是MVCC

MVCC机制的全称为Multi-Version Concurrency Control,即多版本并发控制。

MVCC主要是为了提升数据库并发性能而设计的,其中采用更好的方式处理了读-写并发冲突,做到即使有读写冲突时,可以实现并发执行,从而提升并发能力,确保了任何时刻的读操作都是非阻塞的。

在众多的MySQL开源存储引擎中,几乎只有InnoDB实现了MVCC机制,其他的存储引擎如:MyISAM、memory等存储引擎中并未实现MVCC。

MVCC(Multi-Version Concurrency Control,多版本并发控制)一种并发控制机制,用于解决并发事务访问数据库时可能出现的一些问题,如脏读、不可重复读和幻读。

在MVCC机制中,数据库中的每个数据行都可以存在多个版本,并且每个事务看到的数据版本可能不同。具体来说,MVCC机制通过以下方式实现并发控制:

(1) 版本控制:

每当对数据库中的数据行进行更新操作时,不是直接覆盖原始数据,而是创建一个新的数据版本,并将新版本的数据与事务的时间戳相关联。
(2) 快照读取:

在MVCC中,读取操作不会阻塞写入操作,也不会阻塞其他读取操作。事务可以读取数据库中的数据快照,即某个时间点之前的数据版本,而不会受到其他事务的影响。
(3) 可见性判断:

在执行读取操作时,事务只能看到在其开始之前已经提交的数据版本,而看不到其他事务正在修改的数据。这样可以避免脏读和不可重复读问题。

(4) 回滚操作:

当事务回滚时,不会对数据库中的数据进行物理删除或修改,而是标记事务所涉及的数据版本为无效,使得其他事务无法看到该版本。

总的来说,MVCC机制通过维护多个数据版本,实现了事务的隔离性和并发性,保证了数据库的一致性和可靠性。它是许多现代数据库系统(如MySQL、PostgreSQL等)中常用的并发控制技术。

MVCC的根本目标:提升并发能力

在并发读写数据库时,读操作可能会不一致的数据(脏读)。

为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问。

由于,加锁会将读写操作串行化,所以不会出现不一致的状态。

但是,读操作会被写操作阻塞,大幅降低读性能。

提升并发的思想:COW思想

Copy-On-Write(COW,写时复制)是一种常见的并发编程思想。

Copy-On-Write基本思想是,当多个线程需要对共享数据进行修改时,不直接在原始数据上进行操作,而是先将原始数据复制一份(即写时复制),然后在副本上进行Write。

Copy-On-Write 通过操作副本,可以避免多个线程之间的数据冲突,提高了并发性能。

Copy-On-Write的实现步骤如下:

(1) 读取数据:多个线程同时读取共享数据时,它们可以直接访问原始数据,而不需要复制。因为读取操作不会修改数据,所以可以安全地共享原始数据。
(2) 写入数据:当某个线程需要修改共享数据时,首先会将原始数据进行复制(即写时复制),然后在副本上进行修改。这样做的好处是,其他线程仍然可以继续读取原始数据,不受写入线程的影响。
(3) 更新引用:写入线程完成修改后,会更新共享数据的引用,使得其他线程后续访问时可以获取到最新的数据副本。

Copy-On-Write的优点包括:

  • 线程安全:通过复制数据副本并在副本上进行修改,避免了多线程并发修改原始数据时的数据冲突问题,从而提高了线程安全性。
  • 减少锁竞争:由于读取操作不需要加锁,所以可以减少锁竞争,提高了并发性能。
  • 节省内存:只有在有写入操作时才会进行数据复制,而读取操作可以共享原始数据,因此可以节省内存空间。

然而,Copy-On-Write也有一些缺点,主要是由于数据复制和更新引用所带来的额外开销,可能会导致内存和性能方面的消耗增加。因此,适用场景需要根据具体情况进行评估和选择。

COW思想写操作之间是要互斥的,并且每次写操作都会有一次copy,所以只适合读大于写的情况。所以,COW思想 专门用于优化读的次数远大于写次数的场景。比如,Java的 并发容器CopyOnWriteArrayList。

Java中的CopyOnWriteArrayList

CopyOnWriteArrayList 是jdk1.5以后并发包中提供的一种并发容器,写操作通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也成为“写时复制容器”。

public boolean add(E e) {
   
   
   //加锁,对写操作保证线程安全
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
   
   
       Object[] elements = getArray();
       int len = elements.length;
       //拷贝原容器,长度为原容器+1
       Object[] newElements = Arrays.copyOf(elements, len + 1);
       //在新副本执行添加操作
       newElements[len] = e;
       //底层数组指向新的数组
       setArray(newElements);
       return true;
   } finally {
   
   
       lock.unlock();
   }
}

img

为啥MVCC要使用Copy-On-Write思想呢?借鸡生蛋

总之 MVCC Copy-On-Write思想, 包括三个组成部分:

为啥MVCC要使用Copy-On-Write思想呢?

主要是MVCC 是结合事务使用的,事务为何实现隔离性,每一个事务都需要有自己的操作版本,引入了一个数据副本维护机制 undo-log ,也就是重做日志,

所以, MVCC 也就复用 这个 undo-log 机制, 实现了自己 Copy-On-Read 思想。

MVCC与锁的关系

一图胜千言,40岁老架构师用一张图,给大家总结一下MVCC和锁如何结合使用,提升事务并行能力的:

MVCC(Multi-Version Concurrency Control,多版本并发控制)和锁是数据库管理系统中两种不同的并发控制机制,它们在处理事务并发访问时起着不同的作用。

(1) MVCC:

  • MVCC通过维护数据的多个版本来实现并发控制,允许事务并发访问数据库而不会发生阻塞。
  • 在MVCC中,读取操作不会阻塞写入操作,也不会阻塞其他读取操作。每个事务可以看到一个一致性的数据快照,而不受其他事务的影响。
  • MVCC主要用于读取操作的并发控制,可以有效地避免脏读、不可重复读和幻读等并发问题。

(2) 锁:

  • 锁是一种悲观并发控制机制,通过在事务访问数据时对数据进行加锁,以防止其他事务对该数据进行修改或读取。

  • 在使用锁进行并发控制时,可能会出现阻塞和死锁等问题,特别是在高并发的情况下,锁的粒度过大或者锁的竞争过于激烈时,性能可能会受到影响。

MVCC和锁之间的关系可以总结如下:

  • MVCC是一种 乐观的并发控制机制,通过多副本的版本控制来实现并发访问,而不需要对数据进行加锁。
  • 锁是一种 悲观的并发控制机制,通过对数据进行加锁来确保事务的隔离性和一致性。

40岁老架构师尼恩提示: 很多时候,MVCC和锁可以结合使用,以实现更细粒度的并发控制,提高系统的性能和并发能力。

MySQL事务隔离级别与MVCC

什么是事务

事务(Transaction)是数据库管理系统执行过程中的一个逻辑单位,它由一个有限的数据库操作序列构成。

这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。

事务的目的是确保数据的完整性和一致性,它通过一系列的操作,将数据库从一个一致性状态转换到另一个一致性状态。

事务的ACID特性

事务通常具有以下四个特性,也被称为ACID属性:

(1) 原子性(Atomicity):事务作为一个整体执行,包含在其中的对数据库的操作要么全部执行,要么全部不执行。

(2) 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态。也就是说,一个事务的执行不能破坏数据库数据的完整性和一致性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值