当前位置: 首页 > 后端技术 > Java

采访Pop:MVCC和间隙锁有什么区别?

时间:2023-04-01 13:32:05 Java

MVCC和gaplock是两种完全不同的机制,但是它们的目的是一样的,都是用来保证对数据库的并发访问,我们先来看看两者的定义。MVCC定义MVCC是多版本并发控制(Multi-VersionConcurrencyControl)的缩写,是一种并发控制的方法。在MVCC中,每次读操作都会看到一个固定版本的数据库记录,即使在并发环境下,也不会有读到其他事务还没有提交的数据。MVCC通过在某个时间点保留数据的快照来做到这一点。读取数据时,只会读取该时间点之前提交的数据。在写入数据时,每次写入操作都会创建一个新版本的数据,而不是直接覆盖原始数据。这样读操作可以读取旧版本的数据,写操作可以写入新版本的数据,从而实现并发控制。在MySQL中,InnoDB存储引擎使用MVCC来实现并发控制。间隙锁定义间隙锁是一种锁定索引范围而不是实际数据的锁。它可以锁定一个范围,防止其他事务向这个范围内插入数据,从而保证该范围内数据的唯一性。在MySQL中,InnoDB存储引擎支持间隙锁。InnoDB存储引擎在使用SELECT...FORUPDATE或SELECT...LOCKINSHAREMODE语句时自动使用间隙锁来锁定索引范围。如果一个事务持有一个间隙上的锁,其他事务不能在间隙上插入数据,但可以在间隙之前或之后插入数据。为什么是MVCC?为什么在已经存在防止并发访问的锁的情况下还需要MVCC?MVCC的诞生主要是出于性能的考虑,因为MVCC没有使用锁,它使用多版本的并发控制来实现对数据库的并发访问,这在性能上要好很多。MVCC实现原理MVCC这么强,那么它是如何实现的呢?简单来说,MVCC是通过以下三大组件实现的:隐藏字段:每条执行的SQL命令都有若干个隐藏字段,其中有一个事务ID字段,这个字段非常重要。undolog(回滚日志):记录SQL命令执行的历史数据。ReadView(读视图):包含snapshotread(数据库中保存某一时刻数据的快照)和一些重要的属性。它的实现原理很简单,就是将SQL中的隐藏字段事务ID(自身版本号)与ReadView中的属性版本号进行比较,然后决定使用ReadView中的快照还是undolog中的历史数据(比较规则是MVCC机制的规定,本文不再赘述),最后返回匹配数据。MVCC能解决幻读吗?幻读是指在一个事务中,第一次查询某个范围内的数据时,发现有一些数据符合条件,但再次查询同一个范围时,又发现了一些或多或少的数据。这种情况称为幻读。幻读是由并发事务中的数据修改操作引起的。例如,在一个事务中,另一个事务插入了一条符合条件的数据,导致第二次查询时多了一条数据。MVCC机制可以解决一些幻读问题。MVCC通过保存某个时间点的数据快照来解决(部分)幻读问题。读取数据时,MVCC会根据快照判断可见数据的版本。这样即使其他事务在读取数据的同时修改了数据,也不会影响当前事务的读取结果。因此,MVCC可以有效解决这部分幻读问题。但是需要注意的是,MVCC只能解决读取数据时的幻读问题。对于写数据时的幻读问题,也需要配合锁机制或者使用更高的事务隔离级别(序列化)来解决。也就是说,如果要彻底解决MySQLInnoDB中RR(REPEATABLEREAD)事务隔离级别的幻读问题,需要使用MVCC+锁机制来实现。锁的分类MySQLInnoDB中的锁机制不仅包括间隙锁,还包括行锁和临时锁。行锁、间隙锁和临时构造锁有什么区别?行锁、间隙锁、临时锁都是MySQL中的锁机制。它们的区别在于:行锁是针对一行数据加锁的,可以防止其他事务修改该行数据。间隙锁是对一定范围内的数据加锁,防止其他事务在这个范围内插入数据。临时锁是行锁和间隙锁的组合。可以理解为一种特殊的间隙锁,等于行锁+间隙锁。除了对记录本身加锁外,它还对索引之间的间隙进行加锁,即锁定一段左开右闭的索引范围。总结MVCC和锁机制解决了MySQLInnoDB中RR事务隔离级别的幻读问题,而MySQL中的锁有很多种,如行锁、间隙锁、临时锁等。本文已收录在Gitee开源仓库《Java 面试突击》,其中包括:Redis、JVM、并发、并发、MySQL、Spring、SpringMVC、SpringBoot、SpringCloud、MyBatis、设计模式、消息队列等模块。一次Java面试就够了:最全的Java面试题库(2023版),持续更新...