面试突击:MVCC 和间隙锁有什么区别?
MVCC 和间隙锁是两种完全不同的机制,但它们的目的都是相同的,都是用来保证数据库并发访问的,我们先来看二者的定义。
MVCC 定义
MVCC 是多版本并发控制(Multi-Version Concurrency Control)的缩写,是一种并发控制的方法。
在 MVCC 中,每个读操作会看到一个固定版本的数据库记录,即使在并发环境中,也不会出现读取到了其他事务还未提交的数据的情况。
MVCC 通过保存数据在某个时间点的快照来实现这一点。在读取数据时,只会读取在该时间点之前提交的数据。在写入数据时,会为每个写入操作创建一个新版本的数据,而不是直接覆盖原有的数据。这样,读操作就可以读取旧版本的数据,而写操作则可以写入新版本的数据,从而实现了并发控制。
在 MySQL 中,InnoDB 存储引擎就是使用 MVCC 来实现并发控制的。
间隙锁定义
间隙锁是一种锁定索引范围而非实际数据的锁,它可以锁定一个范围,防止其他事务在这个范围内插入数据,从而保证了范围内的数据的唯一性。在 MySQL 中,InnoDB 存储引擎支持间隙锁。当使用 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE 语句时,InnoDB 存储引擎会自动使用间隙锁来锁定索引范围。
如果一个事务在一个间隙上持有了锁,那么其他事务就不能在这个间隙上插入数据,但是可以在这个间隙之前或之后的位置插入数据。
为什么要有 MVCC?
既然已经有锁可以防止并发访问了,那为什么还需要 MVCC 呢?
MVCC 的诞生主要是出于性能的考虑,因为 MVCC 中没有用到锁,它是通过多版本并发控制的手段来实现数据库并发访问的,这样相比于加锁性能就会好很多。
MVCC 实现原理
MVCC 竟然这么强,那它是怎么实现的呢?
简单来说 MVCC 是通过以下 3 大组件实现的:
- 隐藏字段:每个执行的 SQL 命令都有几个隐藏的字段,其中有一个事务 ID 字段,很重要。
- undo log(回滚日志):里面记录了 SQL 命令执行的历史数据。
- Read View(读视图):包含快照读(一个快照,保存了数据库某个时刻的数据)和一些重要的属性。
它的实现原理简单来说,是通过 SQL 中隐藏的字段事务 ID(自己的版本号)和 Read View 中的属性版本号进行对比,对比之后决定使用 Read View 中的快照或 undo log 中的历史数据(对比的规则是 MVCC 机制的规定,本文不展开讨论),最后再将符合的数据返回。
MVCC 可以解决幻读吗?
幻读是指在一个事务中,第一次查询某个范围的数据时,发现有一些数据符合条件,但是当再次查询同样的范围时,却发现多了一些或者少了一些数据。这种情况就被称为幻读。幻读是由于并发事务中的数据修改操作导致的,比如在一个事务中,另一个事务插入了一条符合条件的数据,导致第二次查询时多了一条数据。
MVCC 机制可以解决部分幻读问题,MVCC 是通过保存数据在某个时间点的快照来实现来解决(部分)幻读问题的,在读取数据时,MVCC 会根据快照来确定可见的数据版本。这样,即使其他事务在读取数据时进行了修改,也不会影响当前事务的读取结果。
因此,MVCC 可以有效地解决这部分幻读问题。但需要注意的是,MVCC 只能解决读取数据时的幻读问题,对于写入数据时的幻读问题,还需要配合锁机制或使用更高的事务隔离级别(串行化)来解决。
也就是说,想要彻底解决 MySQL InnoDB 中 RR(REPEATABLE READ,可重复读)事务隔离级别的幻读问题,需要使用 MVCC + 锁机制共同来实现。
锁分类
在 MySQL InnoDB 中的锁机制不止有间隙锁,还有行锁和临建锁等。
行锁、间隙锁和临建锁有什么区别?
行锁、间隙锁和临建锁都是 MySQL 中的锁机制,它们的区别如下:
- 行锁是针对某一行数据进行的锁定,可以防止其他事务修改该行数据。
- 间隙锁是针对某一范围的数据进行的锁定,可以防止其他事务在该范围内插入数据。
- 临建锁是行锁和间隙锁的组合,可以理解为一种特殊的间隙锁,它等于行锁+间隙锁,除了锁住记录本身,还会锁住索引之间的间隙,即锁定一段左开右闭的索引区间。
小结
MVCC 和锁机制解决了 MySQL InnoDB 中 RR 事务隔离级别的幻读问题,而 MySQL 中的锁类型又有很多种,如行锁、间隙锁、临建锁等。
本文已收录到 Gitee 开源仓库《Java 面试突击》,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。Java 面试有它就够了:最全 Java 面试题库(2023版),持续更新...
面试突击:MVCC 和间隙锁有什么区别?的更多相关文章
- mysql幻读、MVCC、间隙锁、意向锁(IX\IS)
IO即性能 顺序主键写性能很高,由于B+树的结构,主键如果是顺序的,则磁盘页的数据会按顺序填充,减少数据移动,随机主键则可能由于记录移动产生很多io 查询二级索引时,会再根据主键id获取数据页,产生一 ...
- Mysql 间隙锁原理,以及Repeatable Read隔离级别下可以防止幻读原理(百度)
Mysql知识实在太丰富了,前几天百度的面试官问我MySql在Repeatable Read下面是否会有幻读出现,我说按照事务的特性当然会有, 但是面试官却说 Mysql 在Repeatable Re ...
- 【Java面试】为什么引入偏向锁、轻量级锁,介绍下升级流程
Hi,我是Mic 一个工作了7年的粉丝来找我,他说最近被各种锁搞晕了. 比如,共享锁.排它锁.偏向锁.轻量级锁.自旋锁.重量级锁. 间隙锁.临键锁.意向锁.读写锁.乐观锁.悲观锁.表锁.行锁. 然后前 ...
- MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?
大家好,我是小林. 是不是很多人都对 MySQL 加行级锁的规则搞的迷迷糊糊,一会是 next-key 锁,一会是间隙锁,一会又是记录锁. 坦白说,确实还挺复杂的,但是好在我找点了点规律,也知道如何如 ...
- mysql锁机制之间隙锁(Next-Key锁)(五)
间隙锁(Next-Key锁) 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的 索引项加锁:对于键值在条件范围内但并不存在的记录,叫做“间隙(GA ...
- mysql 隔离级别与间隙锁等
数据库隔离级 SQL标准中DB隔离级别有: read uncommitted:可以读到其它transaction 未提交数据 read committed:可以读到其它transaction 已提交数 ...
- 《【面试突击】— Redis篇》-- Redis的线程模型了解吗?为啥单线程效率还这么高?
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的线程模型了解吗?为啥单线程效率还这 ...
- 视频+图文串讲:MySQL 行锁、间隙锁、Next-Key-Lock、以及实现记录存在的话就更新,如果记录不存在的话就插入如何保证并发安全
导读 Hi,大家好!我是白日梦!本文是MySQL专题的第 27 篇. 下文还是白日梦以自导自演的方式,围绕"如何实现记录存在的话就更新,如果记录不存在的话就插入."展开本话题.看看 ...
- MySQL锁(表锁,行锁,共享锁,排它锁,间隙锁)使用详解
锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是协调多个进程或县城并发访问某一资源的一种机制.在数据库当中,除了传统的计算资源(CPU.RAM.I/O等等)的争用之外,数据也是一 ...
- Mysql Innodb 间隙锁浅析
间隙锁说明 innodb引擎自动使用间隙锁来避免幻读(原因是因为innodb采用单行锁+间隙锁组合而成的行锁,会锁定一个范围和记录本身的行),参数默认innodb_locaks_unsafe_for_ ...
随机推荐
- 浏览器输入URL发生了什么:DNS解析、TCP握手、HTTP缓存、重定向、服务器状态码、渲染引擎和JS引擎互斥、渲染过程、浏览器进程、网络进程、渲染进程
输入地址,浏览器查找域名的 IP 地址. 浏览器向 该 IP 地址的web 服务器发送一个 HTTP 请求, 在发送请求之前浏览器和服务器建立TCP的三次握手,判断是否是HTTP缓存, 如果是强制缓存 ...
- LeetCode系列之 (JavaScript) => 88. 合并两个有序数组
题目描述: [Leetcode 题目链接]:88. 合并两个有序数组 - 力扣(LeetCode) (leetcode-cn.com) 解题思路分析: 在nums1中找到nums2 插入的位置,然后在 ...
- 使用Python实现给企业微信发送allure报告,并实现微信查看
1.注册企业微信 搜索企业微信直接注册 2.创建应用 3.查看企业id.Secret.应用id.部门id 4.发送代码 import os import jenkins import requests ...
- swagger接口测试
导入依赖:<!-- swagger start --><dependency> <groupId>io.springfox</groupId> < ...
- 20220720 第七组 陈美娜 Java String用法
关于String引用数据类型 1.字符串中,两个变量的==指的是虚地址 2.String一旦声明不可改变:赋值进去,原值不会被替代.原值也可能指向其他地址: 3.s.length():字符的个数 4. ...
- Deformable DETR (ICLR2021)
Pre-Trained Image Processing Transformer paper:https://arxiv.org/abs/2010.04159 code:https://github. ...
- docker知识篇
什么是Docker?Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机).b ...
- C输入输出
由于刚开始学的是cin和cout进行输入和输出,好多时候就不会写printf和scanf,所以导致有时候程序运行超时也不会改正,所以今天先说一说scanf和printf. 这是cin和cout的格式: ...
- django_ORM基础字段和选项
一.修改ORM 1.任何关于表结构的修改,务必在对应模型类上修改. 2.在上一篇博文中,创建了bookstore_book表,如果需要再添加一个名为info(varchar 100)的字段,则需要如下 ...
- rust 条件编译 Debug Release
#[cfg(debug_assertions)] macro_rules! debug { () => (std::println!()); ($($arg:tt)*) => ({ pri ...