浅谈Innodb中的幻读以及对行级锁的实现

本文深入探讨了MySQL InnoDB引擎在REPEATABLE READ隔离级别下如何通过行级锁解决幻读问题。详细阐述了幻读的定义、REPEATABLE READ级别的幻读解决方案,以及InnoDB中Record Locks、Gap Locks、Next-Key Locks等行级锁的实现原理,通过实验展示了不同场景下的加锁情况。
摘要由CSDN通过智能技术生成

导读

我们都知道,在RR级别下,MySQL的InnoDB引擎通过MVCC(多版本并发控制,Multi-Version Concurrency Control)机制,解决了脏读和不可重复读的问题,同时无锁的设计极大提高了其性能。但是MVCC不能解决幻读的问题。因此,InnoDB引擎使用行锁来解决这个问题。在本文中,首先探讨在MySQL中的幻读(Phantom Rows)究竟是怎样一种现象,然后再对InnoDB中的行级锁的实现进行讨论,并探究各种情况下加锁的具体情况。

准备

在开始之前,首先要说明本文的文档和实验都基于MySQL8.0版本,用到的表和数据如下。

# 建表信息
CREATE TABLE `lock_test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `num` int DEFAULT NULL,
  `no_index` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `num` (`num`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
# 插入数据
insert into lock_test(id,num,no_index) values(15,20,5),(20,30,15),(25,40,20);

幻读(Phantom Rows)

什么是幻读?

在网络上,关于MySQL的RR级别,能否解决幻读问题其实有一定的争议,有两种常见的说法是RR可以解决幻读问题以及RR可以部分解决幻读问题,但不能完全解决。在讨论能否解决幻读问题(Phantom Rows)之前,首先要清楚什么是幻读问题。在ANSI SQL-92标准和MySQL的官方文档中,对幻读都有着明确的定义。

# ANSI SQL-92 (P1和P2分别是Dirty read和Non-repeatable read)
P3 ("Phantom"): SQL-transaction T1 reads the set of rows N that satisfy some <search condition>. SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the <search condition> used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same <search condition>, it obtains a different collection of rows.
# MySQL8.0 doc
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

可以看到,phantom rows所指是在返回结果是一个集合(set)的时候,前后两次查询返回结果不一致的问题。MySQL文档中的举例为:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

假设原有id为90和102的记录,事务T1中执行该查询,T2执行插入id为101的记录并提交,T1再次执行该查询,两次结果不一致,即发生了幻读问题。个人认为,幻读类似于范围查询的不可重读问题。

REPEATABLE READ级别下有没有幻读?

在厘清幻读的定义后,再来看MySQL的RR级别是否解决了它。答案是肯定的。由于MySQL是通过MVCC和行级锁的机制实现Repeatable Read,不如对快照读和当前读分别进行讨论。对于快照读(snapshot read)来说,一个事务中读到的都是记录的同一快照版本,显然不会出现幻读;对于当前读(current read),MySQL通过Next-key Locks的机制锁定索引间的区间,也解决了幻读问题。

那么,MySQL的RR级别只能部分解决幻读问题是怎么来的呢?我观察了网络上的此类说法,它们通常承认RR可以解决上述提到的幻读问题,但是将下面一种情况也归结到幻读问题,并认为RR级别下没有解决它。

# transcationA
begin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值