【MySQL】可重复读级别下基于Next Key Lock解决幻读
昨天读到了一篇文章[1],里面讲,面试官说mysql的可重复读级别下有解决幻读的方式,最后公布了答案,是在sql后面加for update。这么说倒是没错,但是这种问法给我一种奇怪的感觉,因为for update无论在哪个隔离级别下,都能提供x锁进行锁定防止幻读,而next key lock,是x锁的三种实现算法之一,next key lock,也不应该翻译为间隙锁。下面我们一一讲来。
一,mysql的锁
mysql的锁,
按照读或写,分成s锁和x锁
按照锁的范围,分成表锁和行锁
按照意向锁的读或写,分成is锁和ix锁。其中is锁和ix锁是表锁,但不是真的用排他锁锁表,而是一种共享锁,旨在告诉其他线程表中有s锁或者x锁;而s锁和x锁是真的加了排他锁,s锁是对读共享对写排他,x锁是对其他线程的任何操作都排他,且s锁和x锁都是行锁。
而最后一个,mysql行锁的三种算法。
行锁(Record Lock),只锁单行记录本身。
间隙锁(Gap Lock),锁住记录两边的记录,但是对记录本身,不加锁。
临键锁(Next Key Lock),即锁住记录本身,也锁住记录两边,这种锁的范围是左闭右开。还有一种锁,叫做Previous Key Lock,和Next Key Lock类似,区别只是锁的范围左开右闭。它们都来自于谓词锁,即锁住满足某一查询条件的所有数据项,它不仅包括当前在数据库中满足条件的记录,也包括即将要插入,更新或删除到数据库并满足查询条件的数据项。
下图来自《MySQL技术内幕 InnoDB存储引擎》一书。


第一个需要清晰指出的误区是,Next Key Lock翻译为临键锁[2],而不是间隙锁。next意为下一个,key意为键;而gap指空挡、间隙,因此Gap Lock才是间隙锁。
第二个误区是,Next Key Lock确实能够解决幻读问题,但是不止在可重复读(rr)级别下,你在所有级别下,在sql后面加for update都能施加x锁(有时是临键锁有时是行锁,这个后面讲)解决幻读问题。
二,mysql解决并发问题的机制
mysql有两种解决并发问题的机制,一种叫做基于一致性的非锁定读(Multi Version Concurrent Control, MVCC),也叫快照读;另一种叫做基于一致性的锁定读(Lock Based Concurrent Control, LBCC)也叫当前读。
mysql四种隔离级别,读未提交,就是没有并发控制;读已提交和可重复读默认走的MVCC;串行化走的LBCC;但是不管哪个级别,加了lock in share mode(s锁)和for update(x锁)都是走的LBCC了。
简单来说,读已提交和可重复读不加锁走MVCC,加锁走LBCC。串行化就走LBCC没法走MVCC;读未提交默认没并发控制,加了所走LBCC,不过这种级别应该也应用不广。
MVCC其实就是不直接读取记录本身,只读写操作形成的undo log,undo log其实就是一种数据快照,其中包括记录所有数据,此外还多了一个指向其他undo log的指针(roll_ptr)和生成此undo log的事务id(trix_id),因此MVCC被称为快照读。这些不同事务写操作的undo log形成一个undo log链表,在查询的时候事务去undo log链表中进行查询,读已提交和可重复读的区别就是,读已提交每次查询都生成一个ReadView,而可重复读只有第一次查询生成一个ReadView。ReadView如何控制查询和解决不可重复读问题的,可以看往期文章[3]。
LBCC是直接去读取记录本身,这个没有什么好说的。
需要特别说明的是,MVCC和LBCC都是针对读请求的并发机制,对于写请求,会直接对要修改的行加锁进行操作,写操作在事务中会形成undo log并不持久化到硬盘,事务提交后持久化到硬盘并删除无用的undo log。
三,Next Key Lock如何解决幻读问题
要知道Next Key Lock如何解决幻读问题,首先要知道什么是幻读。幻读问题,简单的说就是a事务进行了两次相同的查询,第二次查询结果比第一次多了一些结果,原因是b事务在a事务两次查询中间,向其查询范围内插入了数据并提交,导致a事务第二次查询范围内多出了这些b事务提交的数据。好,接下来我们看一下例子。
假设有这样的一个sql,其中a是辅助索引,a的值有1、3、5、8、10。
select * from t where a = 5 for update;
由于加了x锁,走的LBCC,x锁的具体实现为临键锁,锁住(3, 5)+5+(5,8),即(3,8)。为什么使用临键锁锁住一整个区域呢,用行锁Record Lock只锁住一行不行吗,毕竟我们的查询条件只是a=5。
答案是不行。行锁的定义就是只锁住一行,而且a是辅助索引,并非唯一索引,意味着a=5可能有多行,只靠Record Lock锁不住多行a=5的记录。不仅如此,还有可能新插入的a=5的记录插入在原本a=5索引的最左侧或最右侧,因此要使用Next Key Lock锁住接近a=5的所有索引值对应的记录。即(3, 5)范围内有可能插入一个新的a=5的记录,(5,8)范围内也有可能插入一个新的a=5的记录,因此要锁住临近a=5的一整个范围。整个可能被插入的范围都被锁住,那么新插入数据的可能性就不存在了,幻读因此不可能出现。
至此,我们解释了为什么不能直接使用行锁来加锁,也解释了临键锁为什么能防止幻读。
四,Next Key Lock降级为Record Lock
前面我们解释了为什么普通索引要使用临键锁。其实还有一种情况,即等值查询时,使用的索引是唯一索引,那么Next Key Lock会被mysql降级为Record Lock。
因为唯一索引的数据是唯一的,不管查找的唯一索引的数据有或者没有,都只需要锁住一行即可,使用行锁锁住一行就能锁住等值查询的要找的那一条记录。
五,没有LBCC,可重复读只靠默认的MVCC能解决幻读问题吗
在可重复读级别下,只靠MVCC能够防止幻读吗?先说答案,部分情况下能,部分情况下,不能。
1,能防止幻读的情况
先说一下能防止幻读的原因。a事务进行了两次相同的查询,b事务在这两次查询中间,插入了在a事务查询范围内的数据,并提交,导致a事务第二次查询比第一次查询多出了数据,这就是幻读,两次相同的查询但是结果不一样,多了数据。
出现这种幻读的情况下,分为两种情况,事务b比事务a早开启,和事务b比事务a晚开启。
(1)假设事务b比事务a早开启,在事务a两次查询中间提交。
那么事务a第一次查询时生成了一个ReadView,在事务a第二次查询时,还会使用这个ReadView去进行查询(因为是可重复读级别下)。首先事务a会发现根据这个ReadView,事务b的trx_id在ReadView的min_trx_id和max_trx_id之间,表示事务b可能是活跃的事务,是不是还需要查看m_ids列表;
第二步,其中的m_ids列表(包括了生成ReadView时所有活跃的事务id)会包含事务b的trx_id,因此会认为事务b还是一个活跃事务,活跃事务的数据属于脏数据,因此不会被事务a读取。
注,ReadView的使用规则,查看文章[3]。
(2),假设事务b比事务a晚开启,在事务a两次查询中间提交。则事务b在提交数据后生成的undo log的trx_id就是事务b的trx_id,事务b要比事务a晚开启,意味着事务b的trx_id比事务a第一次查询时生成的ReadView的max_trx_id要大,则事务a在第二次查询时,可以通过ReadView知道,事务b是生成ReadView以后才开启,则事务a不会读取将来的数据。
两种情况列举下来,均可以避免幻读。
2,不能防止幻读的情况
那么什么时候不能防止幻读呢?在防止幻读时举的例子如下:
a事务进行了两次相同的查询,b事务在这两次查询中间,插入了在a事务查询范围内的数据,并提交,导致a事务第二次查询比第一次查询多出了数据
我们只需要在事务a第二次查询数据前,对事务b提交的数据做修改,然后再进行事务a的第二次查询。只用添加这么一步,就会出现幻读。
这是因为update本身不会根据MVCC,具体说就是ReadView去查看是否可以修改,update本身是加悲观锁直接对记录进行修改的,也就是说在事务b插入并提交以后,事务a是可以找到这条数据并成功修改的,并因此生成了undo log,并且undo log的trx_id就是事务a自己。
此时事务a再进行第二次查询,事务a查到符合范围的数据中,有一个自己修改的undo log快照,符合条件,于是就作为结果展示出来了,因此产生了幻读。
以上,就是关于可重复读、MVCC、LBCC、临键锁、间隙锁的一些解释。
参考文章:
[1],Mysql 间隙锁原理,以及Repeatable Read隔离级别下可以防止幻读原理(百度)
[2],详解 MySql InnoDB中的三种行锁(记录锁、间隙锁与临键锁)
[3],【MySQL】基于MVCC的RR、RC级别事务原理简述
相关文章:
【MySQL】可重复读级别下基于Next Key Lock解决幻读
昨天读到了一篇文章[1],里面讲,面试官说mysql的可重复读级别下有解决幻读的方式,最后公布了答案,是在sql后面加for update。这么说倒是没错,但是这种问法给我一种奇怪的感觉,因为for update无论在哪个隔离级…...
【安全性分析】正式安全分析与非正式安全分析
安全性分析-系列文章目录 第一章 【安全性分析】正式安全分析与非正式安全分析 第二章 【安全性分析】BAN逻辑 (BAN Logic) 文章目录 安全性分析-系列文章目录前言一、正式安全分析1. 理想化模型(如随机预言机模型)2. 标准模型(Standard Model)3. 形式化验证4. 数学证明二…...
【项目开发】高校思政课程实践任务平台—数据库设计
未经许可,不得转载。 文章目录 1、项目需求2、数据库选型3、概念数据模型设计3.1、实体及属性3.2、实体关系3.3、补充说明4、数据库语句4.1、数据库对象创建语句4.2、功能实现的SQL语句4.3、视图创建语句4.4、触发器创建语句5、安全性考虑5.1、用户认证和授权5.2、数据传输安全…...
计算机网络安全应该学习哪些知识?
计算机网络安全是一个广泛而深入的领域,要成为一名专业的网络安全专家,需要系统地学习多个方面的知识。以下是一些关键的学习方向: 一、基础知识计算机网络:学习OSI、TCP/IP模型,网络协议,网络设备工作原理…...
logrotate工具强制日志轮询
说明: 1、通过定时任务logrotate工具每天强制日志轮询并压缩,节省存储空间。 参数说明: 1)/opt/yolov5/logs/.log: 是指要轮转日志文件的路径和名称。 是一个通配符,表示匹配以*.log结尾文件名。 2)daily: 是指日志文件每天轮转一次。 3)dateext: 是指轮转的日志文件名中…...
微服务系列三:微服务核心——网关路由
目录 前言 一、登录存在的问题归纳 二、*微服务网关整体方案 三、认识微服务网关 四、网关鉴权实现 五、OpenFeign微服务间用户标识信息传递实现 六、微服务网关知识追问巩固 前言 本篇文章具体讲解微服务中网关的实现逻辑、用于解决什么样的问题。其中标题中标注* 涉…...
【系统架构设计师】2023年真题论文: 论边云协同的设计与实现(包括解题思路和素材)
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 真题题目(2023年 试题4)解题思路边云协同概念和架构边云协同的关键技术边云协同的设计与实现案例分析论文素材参考真题题目(2023年 试题4) 边云协同是指将边缘计算和云计算相结合,实现边缘设备与云端资源之间…...
vue3记录(第一版)
vue2与vue3的区别 vue2属于选项式API,vue3属于组合式API setup概述 setup是vue3中一个新的配置项,值是一个函数,组件中所用到的数据,方法,计算属性,监视等等,均配置在setup中 vue3中的setup和vue2的data,methods之间有什么关系呢? 因为setup比data解析的早,所以在data中可以…...
R 语言数据导入与导出
R 语言数据导入与导出 数据的导入和导出是数据处理中的重要步骤。R 语言提供了多种方法来读取和写入不同格式的数据文件,包括 CSV、Excel、JSON、SQL 数据库等。本文将介绍如何在 R 语言中进行数据的导入和导出。 1. 导入数据 1.1 读取 CSV 文件 CSV(C…...
kubectl常用命令简介
在之前浅谈Kubernetes集群架构 中介绍了kube-apiserver是提供k8s对内或对外的api请求的唯一入口,本文介绍的 kubectl 是官方的CLI命令行工具,用于与 apiserver 进行通信,将用户在命令行输入的命令,组织并转化为 apiserver 能识别的…...
【小白学机器学习31】 大数定律,中心极限定理,标准正态分布与概率的使用
目录 1 正态分布相关的2个相关定理 1.1 大数定律:(证明了)分布的稳定性 1.2 中心极限定理:(证明了)分布的收敛性 2 使用标准差和概率的2种思路 2.1 标准正态分布的曲线 2.2 两种使用方式 2.3 第1种:按整数倍标准差δ 作为标准使用 2.…...
Go语言基础语法
一、创建工程 说明: (1)go.mod文件是go项目依赖管理文件,相当于前端的package.json,也就是Java项目中的Maven的pom.xml。 二、打印数据到控制台 (1)引入fmt (2)使用fmt…...
CSS层叠/CSS变量和!important的使用
layer components {:root {--theme: red;font-family: serif !important;} } CSS Layers CSS Layers 是一种用于管理和组织样式规则的新机制。它允许开发者定义不同的样式层,以便更好地控制样式的优先级和覆盖关系。通过使用 layer 规则,开发者可以将样…...
提升工作效率的小众神器
🤖宝子们,今天我要给大家分享五款超实用的小众工作软件,让你的工作事半功倍!😎 🌟亿可达 - 自动化办公神器 亿可达是一款自动化办公工具,无需编程知识就能搭建出各种自动化工作流程。界面清新…...
【Python+Pycharm】2024-Python安装配置教程
【PythonPycharm】2024-Python安装配置教程 一、下载装 Python 1、进入Python官网首页,下载最新的Python版本 Download Python | Python.org 选择对应版本下载 安装 测试安装情况 python如果安装失败 在系统环境变量添加安装路径 where pythonwin7安装路径添加…...
systemverilog中clocking的用法
文章目录 1.clocking简介2.clocking实例分析3.重点分析(1)bus定义是不是随便取名的(2)输入输出的定义原则是什么(3)到底如何消除了竞争和冒险(4)没用到的信号如何处理(5&…...
【Python开发】大模型应用开发项目整理
不知不觉已经入职3个月了,同事很好,工作充实,学到了很多东西,大大小小的需求也实现了接近20个。负责2个主要component,数据抓取和利用GenAI做数据提取。 1 背景 提取新闻中事件关键信息,比如人名ÿ…...
Redis 的使⽤和原理
第一章:初识 Redis 1.1盛赞 Redis Redis 是⼀种基于键值对(key-value)的 NoSQL 数据库,与很多键值对数据库不同的是,Redis 中的值可以是由 string(字符串)、hash(哈希)、list&…...
前端学Java
一:语法 1、注解 注解(Annotation)是Java中的一种特殊类型的语法,它可以被用来为代码提供元数据。元数据是关于数据的数据,注解可以用于类、方法、变量等的描述与标记。 理解注解可以从以下几个方面入手:…...
VR游戏:多人社交将是VR的下一个风口
第一部分:创业笔记 1. 市场趋势 从单机游戏转向多人互动体验:随着技术的进步,VR游戏正从单机模式向多人互动体验转变。代表作品如Rec Room、Phasmophobia、Among Us和Breachers等,这些游戏的成功证明了多人互动模式的巨大潜力。…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
