【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级别事务原理简述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kaggle “Reducing Commercial Aviation Fatalities” 比赛 生理数据分析

1、背景 Kaggle在2018 年 12 月 20 日举办“Reducing Commercial Aviation Fatalities” 比赛,通过收集飞行员的生理数据,判断飞行员何时会遇到麻烦吗?该比赛主要分析飞行员的问题,因为航班多、时间不固定,飞行员会出…

Python 字符串类型中 ``split(“\n“)`` 与 ``splitlines()`` 方法的一些区别

最近在以 self.__print("#" * 20 "\n") 调用自己写的 __print 接口时发现打印的时候 "\n" 没有打出来,进而发现了 split("\n") 与 splitlines() 方法的一些区别。 一个是参数上,split 需要传递一个字符串作为…

开源库 FloatingActionButton

开源库FloatingActionButton Github:https://github.com/Clans/FloatingActionButton 这个库是在前面这个库android-floating-action-button的基础上修改的,增加了一些更强大和实用的特性。 特性: Android 5.0 以上点击会有水波纹效果 可以选择自定义…

““ 引用类型应用举例

#include <iostream> //使能cin(),cout(); #include <stdlib.h> //使能exit(); #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和resetiosflags(); //setbase( char x )是设置输出数字的基数,如输出进制数则用se…

无人机避障——2D栅格地图pgm格式文件路径规划代码详解

代码和测试效果请看上一篇博客&#xff1a; 无人机避障——使用三维PCD点云生成的2D栅格地图PGM做路径规划-CSDN博客 更换模型文件.dae&#xff1a; 部分模型文件可以从这里下载&#xff1a; https://github.com/ethz-asl/rotors_simulator/wiki 将原先代码中的car.dae文件…

科研项目:利用AI大模型获得基金资助的10个原则

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 以ChatGPT为代表的大语言模型的诞生后&#xff0c;在学术界这些大模型LLM驱动的聊天机器人已经成为大家撰写和修订论文、基金申请书的流行工具。这些LLM经过千亿文本训练&…

CVE-2022-0185

这是一个关于整型溢出的CVE。 static int legacy_parse_param(struct fs_context *fc, struct fs_parameter *param) {struct legacy_fs_context *ctx fc->fs_private; // [1] ctx 与文件描述符相关unsigned int size ctx->data_size; // [2] size —— 目前已经写…

【Linux网络】TCP_Socket

目录 TCP协议&#xff08;传输控制协议&#xff09; listen状态 accept和connect TCP_echo_server (1)创建套接字 &#xff08;2&#xff09;绑定 &#xff08;3&#xff09;设置listen状态 &#xff08;4&#xff09;loop &#xff08;5&#xff09;客户端 多线程远程…

摄像机实时接入分析平台LiteAIServer视频智能分析软件视频诊断中的抖动检测功能

在现代社会中&#xff0c;视频监控系统扮演着至关重要的角色&#xff0c;而视频质量直接影响到监控系统的可靠性和有效性。随着技术的不断进步&#xff0c;视频智能分析软件LiteAIServer作为一款领先的视频智能分析软件&#xff0c;通过引入抖动检测功能&#xff0c;进一步提升…

Excel重新踩坑4:快捷键;逻辑函数;文本函数;日期相关函数;查找与引用函数;统计类函数;数组公式

0、excel常用快捷键 基础快捷键&#xff1a; alt&#xff1a;快速区域求和&#xff1b; ★ altenter&#xff1a;强制换行&#xff08;因为在excel单元格中没法用enter换行&#xff09;&#xff1b;altj&#xff1a;强制换行符的替换删除&#xff0c;这里altj就是在替换中输入…

ABAP RFC SQL 模糊查询和多个区间条件

对于非选择屏幕的情况&#xff0c;RFC接口输入数据后&#xff0c;如何处理字符串模糊查询、日期区间查询、数字区间查询&#xff1a; 一、所有字符支持模糊查询&#xff0c;在SAP SQL中&#xff0c;使用 %S%来实现。 二、区间查询有3种情况&#xff1a; 1、没有值输入&#xf…

python通过pyperclip库操作剪贴板

pyperclip介绍 pyperclip是一个python库用于操作剪贴板&#xff0c;可以非常方便地将文本复制到剪贴板或从剪贴板获取文本。 通过pip进行安装&#xff1a;pip install pyperclip pyperclip的github地址 pyperclip使用 复制到剪贴板 import pypercliptext "Hello, Wo…

Golang | Leetcode Golang题解之第516题最长回文子序列

题目&#xff1a; 题解&#xff1a; func longestPalindromeSubseq(s string) int {n : len(s)dp : make([][]int, n)for i : range dp {dp[i] make([]int, n)}for i : n - 1; i > 0; i-- {dp[i][i] 1for j : i 1; j < n; j {if s[i] s[j] {dp[i][j] dp[i1][j-1] …

Virtuoso使用layout绘制版图、使用Calibre验证DRC和LVS

1 绘制版图 1.1 进入Layout XL 绘制好Schmatic后&#xff0c;在原理图界面点击Launch&#xff0c;点击Layout XL进入版图绘制界面。 1.2 导入元件 1、在Layout XL界面左下角找到Generate All from Source。 2、在Generate Layout界面&#xff0c;选中“Instance”&#…

摩科智能化一体化防盗门(物联网)项目

一&#xff0c;选题依据及意义 ①理论意义 目前国内外学者对智能门锁的研究取得了一些成果&#xff0c;但都局限于猫眼和门锁设计上。本课题在产品设计、服务设计等理论基础上&#xff0c;深入研究在安全与防护的背景下简约化即智能应用的门锁创新。在理论与实际探索上建立了…

记录一下方便的条件编译

1. 需要准备&#xff1a; 1-1、npm i cross-env -D 是跨平台的自定义编译 1-2、构造工具&#xff1a;vite/webpack > vite: import.meta.env.VITE_NODE_ENV > webpack:process.env.NODE_ENV这里使用vite为例子 1-3、 package.json 2. 思路与步骤 首先我们知道 axio…

企业数据泄露安全演练(分享)

该文章主要分享作者在XXX企业内部做的一次【数据泄露安全演练】&#xff0c;涉及演练背景、目的、演练流程、剧本设定、预期行为、结果等等。 以下是完整的演练方案&#xff0c;有不足的地方希望大家指出&#xff01;&#xff01; 需要原版方案电子版的可以联系作者获取。 演练…

[前端面试]计算机网络

TCP/IP 与OSI TCP/IP TCP/IP 四层模型是一个分层网络通信模型&#xff0c; 它将网络通信过程分为四个层次&#xff0c;这四层分别是&#xff1a;网络接口层、互联网层、传输层和应用层。 网络接口层负责在计算机和网络硬件之间传输数据&#xff0c;负责在物理网络上发送和接…

Conmi的正确答案——在Kibana中进入Elasticsearch的索引管理页面

Elasticsearch版本&#xff1a;7.17.25 Kibana版本&#xff1a;7.17.25 注&#xff1a;索引即类似mysql的表。 0、进入首页 1、未创建任何“索引模式”时&#xff1a; 1.1、点击左边的三横菜单&#xff1b; 1.2、点击“Discover”&#xff0c;进入“发现”页面&#xff1b; 2…