1.MySQL面试题之innodb如何解决幻读
1. 写在前面
在数据库系统中,幻读(Phantom Read)是指在一个事务中,两次读取同一范围的数据集时,由于其他事务的插入操作,导致第二次读取结果集发生变化的问题。InnoDB 作为 MySQL 的一个存储引擎,通过多种机制来解决幻读问题,主要包括锁机制和隔离级别。
2. 幻读问题的产生
假设有一个事务 T1,它在某个条件下查询了一批记录。在 T1 进行第一次查询后,如果另一个事务 T2 在 T1 的查询范围内插入了新的记录,那么当 T1 再次查询时,会发现多出了 T2 插入的记录,这就是幻读。
3. InnoDB 如何解决幻读
InnoDB 通过以下两种主要机制来解决幻读问题:
- Next-Key Locks(间隙锁)
- MVCC(多版本并发控制)
3.1 Next-Key Locks
Next-Key Locks(间隙锁)是 InnoDB 存储引擎在实现可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)隔离级别时使用的一种锁机制。它结合了记录锁和间隙锁,用于锁定一个记录及其前后的间隙,防止其他事务在间隙中插入新的记录,从而避免幻读。
3.1.1 组成
Next-Key Locks 是记录锁(Record Lock)和间隙锁(Gap Lock)的组合。具体来说:
- 记录锁(Record Lock):锁定单个记录,防止其他事务对该记录进行修改。
- 间隙锁(Gap Lock):锁定记录之间的间隙,防止其他事务在间隙中插入新的记录。
3.1.2 工作原理
Next-Key Locks 的工作原理是通过锁定一个记录及其前后的间隙,确保在一个事务中,任何插入操作都不会影响到该事务已经读取的数据范围,从而避免幻读。
假设有一个表 employees,包含以下数据:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie');
在可重复读隔离级别下,事务 T1 和 T2 的操作如下:
-- 事务 T1
START TRANSACTION;
SELECT * FROM employees WHERE id BETWEEN 1 AND 3;-- 事务 T2
START TRANSACTION;
INSERT INTO employees (id, name) VALUES (4, 'David');
COMMIT;-- 事务 T1
SELECT * FROM employees WHERE id BETWEEN 1 AND 3;
COMMIT;
在上述操作中,T1 在第一次查询时会锁定 id 在 1 到 3 之间的记录及其前后的间隙:
- 锁定记录 id=1 及其前后的间隙 (-∞, 1]
- 锁定记录 id=2 及其前后的间隙 (1, 2]
- 锁定记录 id=3 及其前后的间隙 (2, 3]
- 锁定记录 id=4 及其前后的间隙 (3, +∞)
由于 T1 使用的是可重复读隔离级别,InnoDB 通过 Next-Key Locks 确保 T1 在第二次查询时,读取的结果集不会受到 T2 插入操作的影响,从而避免了幻读。
3.1.3 Next-Key Locks 的应用场景
Next-Key Locks 主要应用于以下隔离级别:
- 可重复读(REPEATABLE READ):在该隔离级别下,InnoDB 使用 Next-Key Locks 确保在一个事务中,读取的数据集在整个事务期间保持一致,避免幻读。
- 串行化(SERIALIZABLE):在该隔离级别下,InnoDB 通过 Next-Key Locks 确保所有读取操作都加锁,事务之间完全隔离,避免幻读。
3.1.4 Next-Key Locks 的优缺点
优点:
- 避免幻读:通过锁定记录及其前后的间隙,Next-Key Locks 可以有效避免幻读问题。
- 数据一致性:在高并发环境下,Next-Key Locks 可以确保数据的一致性
缺点:
- 锁粒度较大:由于 Next-Key Locks 锁定了记录及其前后的间隙,锁粒度较大,可能会影响并发性能。
- 死锁风险:在高并发环境下,Next-Key Locks 可能会导致死锁,需要进行死锁检测和处理。
死锁的详细原因下面我们展开说。
3.2 间隙锁(Gap Lock)
间隙锁是 Next-Key Locks 的一个重要组成部分,用于锁定记录之间的间隙,防止其他事务在间隙中插入新的记录。间隙锁的范围包括:
- 起始记录之前的间隙,例如 (-∞, 1)
- 两条记录之间的间隙,例如 (1, 2)
- 结束记录之后的间隙,例如 (3, +∞)
通过锁定这些间隙,InnoDB 可以确保在一个事务中,任何插入操作都不会影响到该事务已经读取的数据范围,从而避免幻读。
3.3 MVCC(多版本并发控制)
多版本并发控制(MVCC, Multi-Version Concurrency Control)是一种用于管理数据库并发访问的技术。MVCC 通过为每个事务提供一个一致的视图,确保在高并发环境下,事务可以独立地进行读写操作,而不会相互干扰。InnoDB 存储引擎在实现可重复读(REPEATABLE READ)和读已提交(READ COMMITTED)隔离级别时,广泛使用了 MVCC 技术。
3.3.1 基本原理
MVCC 的核心思想是为每个数据行维护多个版本,并通过版本号或时间戳来区分这些版本。每个事务在读取数据时,会根据事务开始时的快照视图,读取符合其版本号或时间戳的数据。这样,不同事务可以同时读取和写入数据库,而不会相互阻塞。
数据版本
在 InnoDB 中,每行数据都有两个隐藏的列,用于实现 MVCC:
- 事务 ID(Transaction ID):表示创建或最后修改该行数据的事务 ID。
- 回滚指针(Rollback Pointer):指向数据行的前一个版本,用于实现回滚操作。
当一个事务对数据行进行修改时,会创建该数据行的一个新版本,并更新事务 ID 和回滚指针。
3.3.2 实现细节
MVCC 主要通过以下两个操作来实现:
- 快照读(Snapshot Read)
- 当前读(Current Read)
3.3.2.1 快照读(Snapshot Read)
快照读是指事务读取数据时,读取的是数据的快照版本,而不是当前最新的数据。快照版本是事务开始时的数据状态。快照读不会加锁,因此可以实现高效的并发访问。
快照读的典型操作包括:
SELECT 语句(不带 FOR UPDATE 或 LOCK IN SHARE MODE)
这个面试被问过,大家注意
3.3.2.2 当前读(Current Read)
当前读是指事务读取数据时,读取的是当前最新的数据,并且会对读取的数据加锁,以确保数据一致性。当前读通常用于更新操作。
当前读的典型操作包括:
- SELECT … FOR UPDATE
- SELECT … LOCK IN SHARE MODE
- UPDATE
- DELETE
- INSERT
3.3.3 MVCC 在不同隔离级别下的表现
MVCC 在不同的隔离级别下有不同的表现:
- 读未提交(READ UNCOMMITTED):在该隔离级别下,事务可以读取其他事务未提交的数据,不使用 MVCC。
- 读已提交(READ COMMITTED):在该隔离级别下,事务每次读取数据时,读取的是当前最新的已提交版本。MVCC 确保事务读取的数据是已提交的最新版本。
- 可重复读(REPEATABLE READ):在该隔离级别下,事务在整个生命周期内,读取的是事务开始时的一致性视图。MVCC 确保事务读取的数据在整个事务期间保持一致。
- 串行化(SERIALIZABLE):在该隔离级别下,事务之间完全隔离,所有读取操作都加锁,不使用 MVCC。
3.3.4 MVCC 的优缺点
优点:
- 高并发性能:通过快照读,事务可以在不加锁的情况下读取数据,提高了并发性能。
- 减少锁争用:MVCC 避免了读写锁争用问题,提高了系统的吞吐量。
- 数据一致性:通过为每个事务提供一致性视图,MVCC 确保了数据的一致性和隔离性。
缺点:
- 存储开销:由于每行数据需要维护多个版本,MVCC 会增加存储开销。
- 垃圾回收:需要定期清理过期的版本数据,以防止存储空间的浪费。
- 实现复杂:MVCC 的实现需要维护复杂的数据结构和版本管理逻辑。
假设有一个表 employees,包含以下数据:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie');
在可重复读隔离级别下,事务 T1 和 T2 的操作如下:
-- 事务 T1
START TRANSACTION;
SELECT * FROM employees WHERE id = 1;-- 事务 T2
START TRANSACTION;
UPDATE employees SET name = 'Bob Updated' WHERE id = 2;
COMMIT;-- 事务 T1
SELECT * FROM employees WHERE id = 2;
COMMIT;
在上述操作中,T1 在第一次查询时读取了 id=1 的记录。此时,T2 更新了 id=2 的记录,并提交了事务。由于 T1 使用的是可重复读隔离级别,InnoDB 通过 MVCC 确保 T1 在第二次查询时,读取的 id=2 的记录仍然是事务开始时的一致性视图,而不是 T2 更新后的数据。
4. 高并发环境下,Next-Key Locks 死锁分析
在高并发环境下,Next-Key Locks(间隙锁)可能会导致死锁的原因主要包括以下几个方面:
4.1 锁竞争
在高并发环境中,多个事务可能会同时尝试锁定相同的记录或间隙。由于 Next-Key Locks 锁定的范围较大,锁竞争的概率增加。例如,两个事务可能会同时尝试插入不同的记录,但由于间隙锁的存在,它们可能会互相等待对方释放锁,从而导致死锁。
假设有一个表 employees,包含以下数据:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (3, 'Charlie');
在高并发环境下,事务 T1 和 T2 的操作如下:
-- 事务 T1
START TRANSACTION;
SELECT * FROM employees WHERE id = 1;
-- 锁定记录 id=1 及其前后的间隙 (-∞, 1] 和 (1, 3)-- 事务 T2
START TRANSACTION;
SELECT * FROM employees WHERE id = 3;
-- 锁定记录 id=3 及其前后的间隙 (1, 3] 和 (3, +∞)-- 事务 T1
INSERT INTO employees (id, name) VALUES (2, 'Bob');
-- 尝试锁定间隙 (1, 3),但被事务 T2 锁定-- 事务 T2
INSERT INTO employees (id, name) VALUES (2, 'David');
-- 尝试锁定间隙 (1, 3),但被事务 T1 锁定
在上述操作中,T1 和 T2 互相等待对方释放间隙锁,从而导致死锁。
4.2 锁顺序不一致
如果不同事务获取锁的顺序不一致,也可能导致死锁。例如,一个事务先锁定记录 A 再锁定记录 B,而另一个事务先锁定记录 B 再锁定记录 A,这种锁顺序的不一致可能导致两个事务互相等待对方释放锁,从而导致死锁。
假设有一个表 employees,包含以下数据:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie');
在高并发环境下,事务 T1 和 T2 的操作如下:
-- 事务 T1
START TRANSACTION;
SELECT * FROM employees WHERE id = 1;
-- 锁定记录 id=1 及其前后的间隙 (-∞, 1] 和 (1, 2)-- 事务 T2
START TRANSACTION;
SELECT * FROM employees WHERE id = 3;
-- 锁定记录 id=3 及其前后的间隙 (2, 3] 和 (3, +∞)-- 事务 T1
SELECT * FROM employees WHERE id = 3;
-- 尝试锁定记录 id=3 及其前后的间隙 (2, 3] 和 (3, +∞),但被事务 T2 锁定-- 事务 T2
SELECT * FROM employees WHERE id = 1;
-- 尝试锁定记录 id=1 及其前后的间隙 (-∞, 1] 和 (1, 2),但被事务 T1 锁定
在上述操作中,T1 和 T2 获取锁的顺序不一致,导致互相等待对方释放锁,从而导致死锁。
4.3 锁粒度较大
Next-Key Locks 锁定的范围较大,包括记录及其前后的间隙,这增加了锁冲突的概率。在高并发环境下,锁粒度较大的情况下,多个事务可能会同时尝试锁定相同的间隙,从而导致死锁。
假设有一个表 employees,包含以下数据:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (3, 'Charlie');
在高并发环境下,事务 T1 和 T2 的操作如下:
-- 事务 T1
START TRANSACTION;
SELECT * FROM employees WHERE id BETWEEN 1 AND 3;
-- 锁定记录 id=1 和 id=3 及其前后的间隙 (-∞, 1]、(1, 3] 和 (3, +∞)-- 事务 T2
START TRANSACTION;
INSERT INTO employees (id, name) VALUES (2, 'Bob');
-- 尝试锁定间隙 (1, 3),但被事务 T1 锁定-- 事务 T1
INSERT INTO employees (id, name) VALUES (4, 'David');
-- 尝试锁定间隙 (3, +∞),但被事务 T2 锁定
在上述操作中,T1 和 T2 由于锁粒度较大,互相等待对方释放锁,从而导致死锁。
4.4 解决死锁的方法
- 合理设计事务:尽量减少事务的执行时间,避免长时间持有锁。
- 统一锁定顺序:确保不同事务获取锁的顺序一致,避免锁顺序不一致导致的死锁。
- 分解大事务:将大事务分解为多个小事务,减少锁粒度和锁冲突的概率。
- 死锁检测和回滚:InnoDB 内置了死锁检测机制,可以自动检测到死锁并回滚其中一个事务。应用程序可以捕获死锁异常并重试操作。
粉丝福利
博主经营的脱单圈子,定期组织线下免费活动,有兴趣的单身小伙伴可以添加
相关文章:

1.MySQL面试题之innodb如何解决幻读
1. 写在前面 在数据库系统中,幻读(Phantom Read)是指在一个事务中,两次读取同一范围的数据集时,由于其他事务的插入操作,导致第二次读取结果集发生变化的问题。InnoDB 作为 MySQL 的一个存储引擎ÿ…...

Nginx中$http_host、$host、$proxy_host的区别
知识巩固! 网上看到这篇文章,这里转载记录一下。 简介 变量是否显示端口值是否存在 host 浏览器请求的ip,不显示端口 否 "Host:value"显示 值为a:b的时候,只显示a http_host 浏览器请求的ip和端口号 是"Host:v…...

C# Unity 面向对象补全计划 七大原则 之 里氏替换(LSP) 难度:☆☆☆ 总结:子类可以当父类用,牛马是马,骡马也是马
本文仅作学习笔记与交流,不作任何商业用途,作者能力有限,如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识,看不懂没关系 请看专栏:http://t.csdnimg.cn/mIitr,尤其是关于继承的两篇文章ÿ…...

PXE批量安装操作系统
PXE批量安装操作系统 系统环境rhedhat7.9关闭vmware内的dhcp服务 kickstart自动安装脚本的制作 在rhel7系统中提供图形的kickstart制作方式 在rhel8中已经把图形的工具取消,并添加到rhn网络中 在rhel8中如果无法通过rhn网络制作kickstart,可以使用模板…...

float32转float16、snorm/sunorm8/16 学习及实现
1、基础 彻底搞懂float16与float32的计算方式-CSDN博客 例1:float32 0x3fd00000 32b0 011_1111 _1 101_0000_0000_0000_0000_0000 sign0 exp8b0111_1111 h7f d127 >0ffset 127-127 0 mantissa b101_0000_0000_0000_0000_0000(补1,1.1010…...

小型养猫空气净化器怎么选?小型养猫空气净化器产品评测
家养四只猫猫,对于各个角落的猫毛,感觉家里已经被猫毛占领了。感受一下40度高温的养猫人,给掉毛怪疏毛浮毛飘飘,逃不过的饮水机,各个角落,多猫拉臭传来的异味。 一、养猫带来的麻烦 掉毛:每到换…...

数学建模--二分法
目录 二分法的基本原理 应用实例 求解方程根 查找有序数组中的元素 注意事项 Python代码示例 编辑 延伸 二分法在数学建模中的具体应用案例有哪些? 如何选择二分法的初始区间以确保收敛速度和精度? 在使用二分法求解方程时,如何…...

如何使用 Puppeteer 绕过 Akamai
摘要: 本文深入探讨了在面对Akamai强大防护下的网页抓取挑战时,如何运用Puppeteer这一强大的Node.js库,通过模拟真实用户行为、动态请求处理等策略,高效且隐蔽地收集数据。我们将一步步揭开Puppeteer绕过Akamai的神秘面纱&#x…...

【硬件知识】车规级开发等级——AEQ-100和ISO26262标准
文章目录 一、定义二、区别1.应用场景2.使用方法 总结 一、定义 AEQ-100(Automotive Electronics Council Q100)是一个由汽车电子委员会(AEC)制定的标准,主要用于保证汽车电子元件的可靠性。它是一个关于汽车级半导体…...

Qt | QStackedBarSeries(堆叠条形图)+QPercentBarSeries(堆叠百分比条形图)
点击上方"蓝字"关注我们 01、QBarSet 1. 首先,需要创建一个名为QBarSet的类。 2. 在QBarSet类中,定义所需的属性和方法。 3. 属性可能包括条形的名称、颜色、值等。 4. 方法可能包括添加条形、删除条形、计算总和等。 5. 确保QBarSet类能够与QBar类协同工作,…...

C++——多态经典案例(一)组装电脑
案例:小明打算买两台组装电脑,假设电脑零部件包括CPU、GPU和内存组成。 一台电脑使用intel的CPU、GPU和内存条 一台电脑使用Huawei的CPU、GPU和Intel的内存条 分析:使用多态进行实现 将CPU、GPU和内存条定义为抽象类,内部分别定义…...

从传统监控到智能化升级:EasyCVR视频汇聚平台的一站式解决方案
随着科技的飞速发展和社会的不断进步,视频监控已经成为现代社会治安防控、企业管理等场景安全管理中不可或缺的一部分。而在视频监控领域,EasyCVR视频汇聚平台凭借其强大的多协议接入能力,在复杂多变的网络环境中展现出了卓越的性能和广泛的应…...

Windows下,已知程序PID,取得其窗口句柄HWND
我需要实现这么一个功能:在知道某个程序的PID的情况下,最大化并且置顶显示这个程序的窗口。经过一番资料的查找,并且借助了一些科技的力量,找到了解决办法: struct FindWindowData {DWORD processId;HWND hWnd; };BOO…...

Java获取exe文件详细信息:产品名称,产品版本等
使用Maven项目,在pom.xml文件中注入: <dependency><groupId>com.kichik.pecoff4j</groupId><artifactId>pecoff4j</artifactId><version>0.4.1</version></dependency> 程序代码: import …...

ORB-SLAM2运行环境搭建
操作系统:Ubuntu20.04 1.安装Eigen3 推荐大家安装版本 3.2.10 链接:https://eigen.tuxfamily.org/index.php?titleMain_Page mkdir build cd build cmake .. sudo make install2.安装Pangolin 推荐安装0.5版本 链接:https://github.com…...

Nginx高频核心面试题2
目录 高级问题1. **Nginx中如何实现URL重写?**2. **如何在Nginx中设置基本的HTTP身份验证?**3. **如何限制Nginx中的请求速率?**4. **如何在Nginx中设置自定义错误页面?**5. **Nginx的worker_processes和worker_connections参数有…...

全面提升PDF编辑效率,2024年五大顶级PDF编辑器推荐!
在这个数字化飞速发展的时代,PDF文件已经成为我们日常工作和学习中不可或缺的一部分。然而,面对PDF文件的编辑和管理,许多人仍然感到困惑和无助。今天,就让我们一起探索几款高效、易用的PDF编辑器,它们将彻底改变你的工…...

代码随想录算法训练营第二十天|235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点
写在前边的话 235. 二叉搜索树的最近公共祖先 题目链接 力扣题目链接 题目难度 中等 看到题目的第一想法 看到题目的第一想法,除了昨天做过的普通二叉树的最近祖先的解法利用回溯从底向上搜索,我会想到使用迭代法,但我好像不太会使用到二…...

视频美颜SDK与直播美颜插件在实时视频中的应用
视频美颜技术作为提升视频质量的重要手段,已经成为了许多视频和直播应用中不可或缺的一部分。本篇文章,笔者将探讨视频美颜SDK与直播美颜插件在实时视频中的应用,并分析其在用户体验和技术实现方面的重要性。 一、视频美颜SDK的应用场景 视…...

【Linux】yum(工具篇)
文章目录 前言:什么是软件包yum 的介绍yum源yum源的配置第三方源的配置官方源的配置镜像站点安装wget包备份本地yum源配置网易yum源重新生成yum缓存 前言:什么是软件包 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程…...

3GPP入门
官网地址 3GPP – The Mobile Broadband Standard 协议下载链接 Directory Listing /ftp/specs/archive 总纲 重点series Signalling protocols ("stage 3") - user equipment to network24 series信令Radio aspects25 series3G 基础LTE (Evolved UTRA), LTE-Adva…...
FFmpeg内存对齐简述
目录 引文 行字节数的计算 ffmpeg中的align ffmpeg中的linesize 内容参考 引文 在ffmpeg的使用过程中有时会发现align这个参数,那么这个参数代表什么意思,不同的值会产生什么影响呢,详见下文。 行字节数的计算 理解内存对齐之前首先要…...

手机号码归属地查询接口如何对接?(一)
一、什么是手机号码归属地接口? 通过手机号查询归属地信息、是否虚拟运营商等。 二、手机号码归属地接口适用哪些场景? 例如:市场营销领域 (1)精准营销:企业可以通过手机号归属地查询接口了解客户的大致…...

DDei在线设计器-加载数据
加载数据 本示例演示了怎样加载已有的JSON到设计器中。 如需了解详细的API教程以及参数说明,请参考DDei文档 外部数据JSON demo.vue <script setup lang"ts"> import DDeiEditorView from "ddei-editor"; import { DDeiCoreStandLayou…...

NetLLM: Adapting Large Language Models for Networking.
目录 NetLLM: Adapting Large Language Models for Networking.GlossaryNotesINTRODUCTIONThe Main Roadmap so farNew Opportunities and ChallengesDesign and Contributions BACKGROUNDLearning-Based Networking AlgorithmsLarge Language Models MOTIVATIONNETLLM DESIGNM…...

基于Yolov8面部七种表情检测与识别C++模型部署
表情识别 七种表情识别是一个多学科交叉的研究领域,它结合了心理学、认知科学、计算机视觉和机器学习等学科的知识和技术。 基本概念 表情的定义:表情是人们在情绪体验时面部肌肉活动的结果,是人类情感交流的基本方式之一。基本表情理论&a…...

未确认融资费用含义及会计处理流程
文章目录 一、含义二、会计处理流程2.1、初始计量2.2、后续计量2.3、报表列式 三、实务中的注意事项 一、含义 未确认融资费用: 由于企业现有资金不足,购买资产时选择分期支付款项,导致实际支付的款项大于资产的购入价值,两者的差额就是由于…...

Linux配置go程序为service后台开机自启动
1.编写需要启动的项目路径以及简单配置 sudo nano /etc/systemd/system/go.service#定义服务的元数据和依赖关系。 [Unit] #这是对服务的简短描述。 DescriptionMy Go Service #network.target 是一个虚拟目标,它表示网络服务已经初始化完成。该指令告诉 systemd 在…...

汇舟问卷:完成16份调查,挣了40美金,换算后美滋滋
这个世界有太多的人30岁,35岁以后,当初没有去做自己想做的工作,没有花时间去坚持想做的工作,他们在选择这份想做的事业的前提被自己的父母朋友爱人阻断了。 他们告诉你,要努力的做好现在的工作,争取升职…...

Nacos 202407月RCE漏洞(0day)与复现
免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 一、背景与…...