InnoDB如何解决幻读?深入解析MySQL的并发控制机制

news2025/3/21 19:38:46

---

## 一、什么是幻读(Phantom Read)?

**幻读**是数据库事务隔离性中的一个典型问题,具体表现为:  
在同一个事务中,多次执行相同的范围查询(Range Query)时,**后一次查询看到了前一次查询未出现的新记录**。这种现象通常发生在事务未完全隔离的场景下,尤其是在**可重复读(Repeatable Read)**和**读未提交(Read Uncommitted)**隔离级别中。

### 示例场景
1. **事务A**执行查询:`SELECT * FROM users WHERE age > 20;`(返回3条记录)。
2. **事务B**插入一条新记录:`INSERT INTO users (age) VALUES (25);`。
3. **事务A**再次执行相同的查询,发现多了一条记录(共4条)。

这种现象称为“幻读”,如同幻觉般出现了新的数据。

---

## 二、InnoDB如何解决幻读?

InnoDB通过两种核心机制解决幻读问题:  
1. **多版本并发控制(MVCC)**  
2. **间隙锁(Gap Lock) + 临键锁(Next-Key Lock)**

### 1. 多版本并发控制(MVCC)
MVCC通过为每个事务生成一个**一致性视图(Consistent Read View)**,确保事务在多次查询中看到相同的数据快照。  
- **快照读(Snapshot Read)**:普通的`SELECT`语句使用MVCC,读取的是事务开始时的数据版本,不会看到其他事务的插入或删除操作。  
- **当前读(Current Read)**:加锁的`SELECT ... FOR UPDATE`或`SELECT ... LOCK IN SHARE MODE`会读取最新数据并加锁。

**MVCC的作用**:  
- 在`Repeatable Read`隔离级别下,快照读可以避免幻读。  
- 但若事务中存在当前读操作,仍需依赖锁机制。

### 2. 间隙锁(Gap Lock)与临键锁(Next-Key Lock)
#### (1) 间隙锁(Gap Lock)
间隙锁锁定的是索引记录之间的“间隙”,防止其他事务在范围内插入新数据。  
例如,表中现有记录的`age`值为`[10, 20, 30]`,执行`SELECT * FROM users WHERE age > 20 FOR UPDATE`时,InnoDB会锁定`(20, +∞)`的区间。

#### (2) 临键锁(Next-Key Lock)
临键锁是**记录锁(Record Lock) + 间隙锁(Gap Lock)**的组合,锁定索引记录及其之前的间隙。  
例如,索引值为`20`的记录,临键锁会锁定区间`(-∞, 20]`。

**作用**:  
- 防止其他事务在锁定范围内插入新数据,从而避免幻读。

---

## 三、实战验证:InnoDB如何阻止幻读?

### 实验环境
- 数据库:MySQL 8.0
- 表结构:

  ```sql
  CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    age INT NOT NULL,
    INDEX idx_age (age)
  );
  ```

### 步骤1:事务A执行范围查询并加锁
```sql

-- 事务A
BEGIN;
SELECT * FROM users WHERE age > 20 FOR UPDATE; -- 当前读,触发临键锁
-- 此时锁定区间 (20, +∞)


```

### 步骤2:事务B尝试插入数据
```sql

-- 事务B
BEGIN;
INSERT INTO users (age) VALUES (25); -- 被阻塞!
```


事务B的插入操作会被阻塞,直到事务A提交或超时。

### 结果分析
- InnoDB通过临键锁锁定了`age > 20`的范围,阻止事务B插入`age=25`的记录。  
- 因此,事务A的两次查询结果一致,避免了幻读。

---

## 四、InnoDB解决幻读的局限性

1. **仅对当前读有效**  
   MVCC的快照读可以避免幻读,但若事务中混合快照读和当前读,仍需显式加锁。

2. **索引依赖**  
   间隙锁和临键锁依赖于索引。若查询未使用索引,InnoDB会退化为表锁,严重影响性能。

3. **隔离级别限制**  
   - 在`Repeatable Read`级别下,InnoDB默认通过临键锁解决幻读。  
   - 在`Read Committed`级别下,间隙锁会被禁用,无法完全避免幻读。

---

## 五、最佳实践

1. **合理选择隔离级别**  
   - 默认使用`Repeatable Read`,兼顾性能与一致性。  
   - 在需要更高并发时,可降级为`Read Committed`,但需手动处理幻读风险。

2. **显式加锁**  
   对关键范围查询使用`SELECT ... FOR UPDATE`,强制触发临键锁。

3. **优化索引设计**  
   确保查询条件命中索引,避免锁升级为表锁。

---

## 六、总结

InnoDB通过**MVCC的快照读**和**临键锁的当前读**双重机制,在`Repeatable Read`隔离级别下解决了幻读问题。  
- **MVCC**:保证快照读的一致性视图。  
- **临键锁**:通过锁定索引范围,阻止其他事务插入新数据。  

理解这些机制有助于在实际开发中合理设计事务和查询逻辑,确保数据一致性并提升并发性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2299810.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA集成DeepSeek

引言 随着数据量的爆炸式增长,传统搜索技术已无法满足用户对精准、高效搜索的需求。 DeepSeek作为新一代智能搜索技术,凭借其强大的语义理解与深度学习能力,正在改变搜索领域的游戏规则。 对于 Java 开发者而言,将 DeepSeek 集成…

leetcode:627. 变更性别(SQL解法)

难度:简单 SQL Schema > Pandas Schema > Salary 表: ----------------------- | Column Name | Type | ----------------------- | id | int | | name | varchar | | sex | ENUM | | salary | int …

SQLMesh系列教程-3:SQLMesh模型属性详解

SQLMesh 的 MODEL 提供了丰富的属性,用于定义模型的行为、存储、调度、依赖关系等。通过合理配置这些属性,可以构建高效、可维护的数据管道。在 SQLMesh 中,MODEL 是定义数据模型的核心结构,初学SQLMesh,定义模型看到属…

【Leetcode 952】按公因数计算最大组件大小

题干 给定一个由不同正整数的组成的非空数组 nums ,考虑下面的图: 有 nums.length 个节点,按从 nums[0] 到 nums[nums.length - 1] 标记;只有当 nums[i] 和 nums[j] 共用一个大于 1 的公因数时,nums[i] 和 nums[j]之…

【第4章:循环神经网络(RNN)与长短时记忆网络(LSTM)— 4.6 RNN与LSTM的变体与发展趋势】

引言:时间序列的魔法钥匙 在时间的长河中,信息如同涓涓细流,绵延不绝。而如何在这无尽的数据流中捕捉、理解和预测,正是循环神经网络(RNN)及其变体长短时记忆网络(LSTM)所擅长的。今天,我们就来一场深度探索,揭开RNN与LSTM的神秘面纱,看看它们如何在时间序列的海洋…

简单几个步骤完成 Oracle 到金仓数据库(KingbaseES)的迁移目标

作为国产数据库的领军选手,金仓数据库(KingbaseES)凭借其成熟的技术架构和广泛的市场覆盖,在国内众多领域中扮演着至关重要的角色。无论是国家电网、金融行业,还是铁路、医疗等关键领域,金仓数据库都以其卓…

八、SPI读写XT25数据

8.1 SPI 简介 SPI(Serial Peripheral Interface,串行外设接口)是一种同步串行通信协议,广泛用于嵌入式系统中连接微控制器与外围设备,如传感器、存储器、显示屏等。 主要特点 1. 全双工通信:支持同时发送…

Visionpro 齿轮测量

效果展示 一、题目要求 求出最大值,最小值,平均值 二、分析 1.首先要进行模板匹配 2.划清匹配范围 3.匹配小三角的模板匹配 4.卡尺 5.用找圆工具 工具 1.CogPMAlignTool 2.CogCaliperTool 3.CogFindCircleTool 4.CogFixtureTool 三、模板匹…

索引以及索引底层数据结构

一、什么是索引? 索引(index)是数据库高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构(B树),这些数据结构以某种方式指向真在…

开业盛典活动策划方案拆解

道叔来给大家详细剖析咱们方案库里刚收录的这份《蜀大侠火锅店武侠风开业盛典活动策划方案》了,保证让你看完直呼过瘾,收获满满! 一、主题创意:武侠风,直击人心 首先,咱们得夸一下这活动的主题——“XXX‘…

API 接口自动化

HTTP协议 - 白月黑羽 HTTP协议简介 如果客户端是浏览器,如何在chrome浏览器中查看 请求和响应的HTTP消息?按f12-》network 清除当前信息 响应的消息体在Response里看 点preview,可以看响应的消息体展开的格式 HTTP请求消息 请求头 reques…

安全测试|SSRF请求伪造

前言 SSRF漏洞是一种在未能获取服务器权限时,利用服务器漏洞,由攻击者构造请求,服务器端发起请求的安全漏洞,攻击者可以利用该漏洞诱使服务器端应用程序向攻击者选择的任意域发出HTTP请求。 很多Web应用都提供了从其他的服务器上…

智能编程助手功能革新与价值重塑之:GitHub Copilot

引言: GitHub Copilot 的最新更新为开发者带来了显著变化,其中 Agent Mode 功能尤为引人注目。该模式能够自动识别并修复代码错误、自动生成终端命令,并具备多级任务推理能力,这使得开发者在开发复杂功能时,可大幅减少…

物联网行业通识:从入门到深度解析

物联网行业通识:从入门到深度解析 (图1:物联网生态示意图) 一、引言:万物互联时代的到来 根据IDC最新预测,到2025年全球物联网设备连接数将突破410亿,市场规模达1.1万亿美元。物联网&#xff…

ABP - 事件总线之分布式事件总线

ABP - 事件总线之分布式事件总线 1. 分布式事件总线的集成1.2 基于 RabbitMQ 的分布式事件总线 2. 分布式事件总线的使用2.1 发布2.2 订阅2.3 事务和异常处理 3. 自己扩展的分布式事件总线实现 事件总线可以实现代码逻辑的解耦,使代码模块之间功能职责更清晰。而分布…

再谈SpringCloud Gateway源码

再谈SpringCloud Gateway源码 一、整体请求流程二、前置对象准备1、实例化HandlerMapping2、实例化Route3、实例化WebHandler 三、实践业务扩展点1、定义扩展Route对象2、Filter能做什么3、定义扩展Filter对象4、定义父类Filter简化请求参数处理 前言: 之前有阅读过…

把 CSV 文件摄入到 Elasticsearch 中 - CSVES

在我们之前的很多文章里,我有讲到这个话题。在今天的文章中,我们就提重谈。我们使用一种新的方法来实现。这是一个基于 golang 的开源项目。项目的源码在 https://github.com/githubesson/csves/。由于这个原始的代码并不支持 basic security 及带有安全…

C进阶 数据的存储

目录 前言 一,VS的知识储备 二,有趣的scanf()读取 三,数据的存储 引言 四,整数存储 五,小数存储 总结 前言 这里将深入计算机,看计算机是如何进行数据的存储的,怎么在计算机里面筑巢 为…

【c++】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗?

【c】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗? 1.线程终止会导致进程终止吗? 在操作系统中,线程是进程的基本执行单元,一个进程可以包含一个或多个线程。 当一个子线程终止时,进程并不会因此自动终…

springcloud集成gateway

本篇文章只介绍gateway模块的搭建步骤,并无gateway详细介绍 gateway详解请查看:SpringCloudGateway官方文档详解 前置处理 父模块中已指定版本 不知道如何选择版本看这篇: 手把手教你梳理springcloud与springboot与springcloudalibaba的版本…