mysql 插入加锁_Mysql加锁过程详解(9)-innodb下的记录锁,间隙锁,next-key锁

你需要知道的

之前我们介绍了排他锁,其实innodb下的记录锁(也叫行锁),间隙锁,next-key锁统统属于排他锁。

行锁

记录锁其实很好理解,对表中的记录加锁,叫做记录锁,简称行锁。

生活中的间隙锁

编程的思想源于生活,生活中的例子能帮助我们更好的理解一些编程中的思想。

生活中排队的场景,小明,小红,小花三个人依次站成一排,此时,如何让新来的小刚不能站在小红旁边,这时候只要将小红和她前面的小明之间的空隙封锁,将小红和她后面的小花之间的空隙封锁,那么小刚就不能站到小红的旁边。

这里的小红,小明,小花,小刚就是数据库的一条条记录。

他们之间的空隙也就是间隙,而封锁他们之间距离的锁,叫做间隙锁。

Mysql中的间隙锁

下表中(见图一),id为主键,number字段上有非唯一索引的二级索引,有什么方式可以让该表不能再插入number=5的记录?

图一

根据上面生活中的例子,我们自然而然可以想到,只要控制几个点,number=5之前不能插入记录,number=5现有的记录之间不能再插入新的记录,number=5之后不能插入新的记录,那么新的number=5的记录将不能被插入进来。

那么,mysql是如何控制number=5之前,之中,之后不能有新的记录插入呢(防止幻读)?

答案是用间隙锁,在RR级别下,mysql通过间隙锁可以实现锁定number=5之前的间隙,number=5记录之间的间隙,number=5之后的间隙,从而使的新的记录无法被插入进来。

间隙是怎么划分的?

注:为了方面理解,我们规定(id=A,number=B)代表一条字段id=A,字段number=B的记录,(C,D)代表一个区间,代表C-D这个区间范围。

图一中,根据number列,我们可以分为几个区间:(无穷小,2),(2,4),(4,5),(5,5),(5,11),(11,无穷大)。

只要这些区间对应的两个临界记录中间可以插入记录,就认为区间对应的记录之间有间隙。

例如:区间(2,4)分别对应的临界记录是(id=1,number=2),(id=3,number=4),这两条记录中间可以插入(id=2,number=3)等记录,那么就认为(id=1,number=2)与(id=3,number=4)之间存在间隙。

很多人会问,那记录(id=6,number=5)与(id=8,number=5)之间有间隙吗?

答案是有的,(id=6,number=5)与(id=8,number=5)之间可以插入记录(id=7,number=5),因此(id=6,number=5)与(id=8,number=5)之间有间隙的,

间隙锁锁定的区域

根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)。

图一中,where number=5的话,那么间隙锁的区间范围为(4,11);

间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:

(1)防止间隙内有新数据被插入

(2)防止已存在的数据,更新成间隙内的数据(例如防止numer=3的记录通过update变成number=5)

innodb自动使用间隙锁的条件:

(1)必须在RR级别下

(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)

接下来,通过实际操作观察下间隙锁的作用范围

图三 表结构

案例一:

````

session1:

starttransaction;select * from news where number=4 for update;

session2:

starttransaction;insert into news value(2,4);#(阻塞)insert into news value(2,2);#(阻塞)insert into news value(4,4);#(阻塞)insert into news value(4,5);#(阻塞)insert into news value(7,5);#(执行成功)insert into news value(9,5);#(执行成功)insert into news value(11,5);#(执行成功)

````

检索条件number=4,向左取得最靠近的值2作为左区间,向右取得最靠近的5作为右区间,因此,session 1的间隙锁的范围(2,4),(4,5),如下图所示:

间隙锁锁定的区间为(2,4),(4,5),即记录(id=1,number=2)和记录(id=3,number=4)之间间隙会被锁定,记录(id=3,number=4)和记录(id=6,number=5)之间间隙被锁定。

因此记录(id=2,number=4),(id=2,number=2),(id=4,number=4),(id=4,number=5)正好处在(id=3,number=4)和(id=6,number=5)之间,所以插入不了,需要等待锁的释放,而记录(id=7,number=5),(id=9,number=5),(id=11,number=5)不在上述锁定的范围内,因此都会插入成功。

案例二:

````

session1:

starttransaction;select * from news where number=13 for update;

session2:

starttransaction;insert into news value(11,5);#(执行成功)insert into news value(12,11);#(执行成功)insert into news value(14,11);#(阻塞)insert into news value(15,12);#(阻塞)update news set id=14 where number=11;#(阻塞)update news set id=11 where number=11;#(执行成功)

````

检索条件number=13,向左取得最靠近的值11作为左区间,向右由于没有记录因此取得无穷大作为右区间,因此,session 1的间隙锁的范围(11,无穷大),如下图所示:

此表中没有number=13的记录的,innodb依然会为该记录左右两侧加间隙锁,间隙锁的范围(11,无穷大)。

有人会问,为啥update news set id=14 where number=11会阻塞,但是update news set id=11 where number=11却执行成功呢?

间隙锁采用在指定记录的前面和后面以及中间的间隙上加间隙锁的方式避免数据被插入,此图间隙锁锁定的区域是(11,无穷大),也就是记录(id=13,number=11)之后不能再插入记录,update news set id=14 where number=11这条语句如果执行的话,将会被插入到(id=13,number=11)的后面,也就是在区间(11,无穷大)之间,由于该区间被间隙锁锁定,所以只能阻塞等待,而update news set id=11 where number=11执行后是会被插入到(id=13,number=11)的记录前面,也就不在(11,无穷大)的范围内,所以无需等待,执行成功。

案例三:

````

session1:

starttransaction;select * from news where number=5 for update;

session2:

starttransaction;insert into news value(4,4);#(阻塞)insert into news value(4,5);#(阻塞)insert into news value(5,5);#(阻塞)insert into news value(7,11);#(阻塞)insert into news value(9,12);#(执行成功)insert into news value(12,11);#(阻塞)update news set number=5 where id=1;#(阻塞)update news set id=11 where number=11;#(阻塞)update news set id=2 where number=4;#(执行成功)update news set id=4 where number=4;#(阻塞)

````

检索条件number=5,向左取得最靠近的值4作为左区间,向右取得11为右区间,因此,session 1的间隙锁的范围(4,5),(5,11),如下图所示:

有人会问,为啥insert into news value(9,12)会执行成功?间隙锁采用在指定记录的前面和后面以及中间的间隙上加间隙锁的方式避免数据被插入,(id=9,number=12)很明显在记录(13,11)的后面,因此不再锁定的间隙范围内。

为啥update news set number=5 where id=1会阻塞?

number=5的记录的前面,后面包括中间都被封锁了,你这个update news set number=5 where id=1根本没法执行,因为innodb已经把你可以存放的位置都锁定了,因为只能等待。

同理,update news set id=11 where number=11由于记录(id=10,number=5)与记录(id=13,number=11)中间的间隙被封锁了,你这句sql也没法执行,必须等待,因为存放的位置被封锁了。

案例四:

session 1:

starttransaction;select * from news where number>4 for update;

session2:

starttransaction;update news set id=2 where number=4;#(执行成功)update news set id=4 where number=4;#(阻塞)update news set id=5 where number=5;#(阻塞)insert into news value(2,3);#(执行成功)insert into news value(null,13);#(阻塞)

检索条件number>4,向左取得最靠近的值4作为左区间,向右取无穷大,因此,session 1的间隙锁的范围(4,无穷大),如下图所示:

session2中之所以有些阻塞,有些执行成功,其实就是因为插入的区域被锁定,从而阻塞。

next-key锁

next-key锁其实包含了记录锁和间隙锁,即锁定一个范围,并且锁定记录本身,InnoDB默认加锁方式是next-key 锁。

上面的案例一session 1中的sql是:select * from news where number=4 for update ;

next-key锁锁定的范围为间隙锁+记录锁,即区间(2,4),(4,5)加间隙锁,同时number=4的记录加记录锁。

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

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

相关文章

string.intern_使用String.intern()减少内存使用

string.intern时不时地会有一个垂死的生产应用程序。 而且您知道您需要尽快对其进行修补。 我们也是如此,并认为分享最近的一个战争故事会很有趣。 在这种情况下,我们就有机会使用String.intern()之类的简单补丁来修补应用程序。 …

测量string变量长度函数_利用Graphics::MeasureString函数测量字符串的宽度,高度

我就吐一句槽,今天被这个函数完虐....当我们需要获得一个字符串的长度时(注意,不是length,这只是返回该字符串的字符个数),我们需要知道的是一个字符串的长度也就是一个字符串的宽,说到底就是像素大小,没错…

首选System.lineSeparator()以用Java编写系统相关的行分隔符字符串

JDK 7在java.lang.System类上引入了一个名为lineSeparator()的新方法。 该方法不期待任何参数,并返回一个String ,它表示“取决于系统的行分隔符字符串。” 此方法的Javadoc文档还指出System.lineSeparator() “始终返回相同的值–…

微信批量退款php,微信支付退款接口详解

微信支付有2个退款相关的接口,分别是申请退款API和查询退款API,这2个接口在实际微信支付开发中都会用到。其中申请退款API因为安全性,需要使用证书,证书在商户平台后台下载.申请退款接口支持一年以内的订单退款,可以分…

1235813找规律第100个数_人教版一年级下册数学第1-8单元知识点梳理填空,附答案...

参考答案:第一单元 认识图形1、认识平面图形 2、平面图形的拼组用相同的正方形、长方形或三角形可以分别拼成更大的正方形、长方形或三角形。3、认识七巧板 七巧板是由1个正方形、1个平行四边形、5个三角形组成的。第二单元 20以内的退位减法1、十几减几的计算方法(…

php m grep event,php-如何杀死与30分钟以上的grep匹配的进程?

我有一组并行运行的进程.有时有些闲荡时间超出了脚本的预期范围&#xff1a;$time_start microtime(true)$max_run_time 30 * 60; // 30 minutes, measured in secondswhile ((microtime(true)-$time_start) < $max_run_time) {// do stuff, but quit after 30 minutes}我…

透视变换–鸟瞰图_单例设计模式–鸟瞰

透视变换–鸟瞰图几天前&#xff0c;当我回到家乡时&#xff0c;我的一位来自同事的准青年参加了一家跨国公司的采访&#xff0c;在采访过程中受了重伤。 我的意思是&#xff0c;由于面试小组提出了一些难题&#xff0c;他无法使面试合格。 当我回到班加罗尔时&#xff0c;他分…

pandas整表写入excel指定位置_当Python遇到Excel,一个能打的都没有~

几乎人人都在用Excel&#xff0c;这种极易上手的数据分析工具无处不在&#xff0c;一旦你掌握了窍门&#xff0c;它就变得非常强大。而Python通常被认为更具有挑战性&#xff0c;但能做的事也更多。当Python遇到Excel会发生什么&#xff1f;本文将告诉你&#xff0c;这三项Exce…

linux用户密码转换为明文,Linux运维知识之linux下抓取内存中明文密码mimipenguin

本文主要向大家介绍了Linux运维知识之linux下抓取内存中明文密码mimipenguin&#xff0c;通过具体的内容向大家展现&#xff0c;希望对大家学习Linux运维知识有所帮助。下载地址&#xff1a;https://github.com/huntergregal/mimipenguin 基本使用语法&#xff1a;rootkali:~/e…

无需再忙了:Lambda-S3缩略图,由SLAppForge Sigma钉牢!

如果你还没有注意到了&#xff0c;我最近被唠叨试图开始使用时&#xff0c;我遭遇了陷阱AWSλ-S3正式例子 。 虽然大多数这些愚蠢的错误的指责是对我自己的懒惰&#xff0c;过度自尊和缺乏对细节的关注&#xff0c;我个人觉得&#xff0c;在开始与一家领先的无服务器供应商不应…

wap(dopra linux )命令,运营商定制的华为光猫Telnet命令恢复华为界面

首先Telnet连接光猫Welcome Visiting Huawei Home GatewayCopyright by Huawei Technologies Co., Ltd.Login:rootPassword:User name or password is wrong, please try it again!Login:rootPassword:adminWAP>suERROR::Command is not existedWAP>lsERROR::Command is …

请简述gouraud光照模型_《计算机图形学》试卷及答案

一、填空题(每空0.5分&#xff0c;共 1 0 分)1、 计算机图形学中的图形是指由点、线、面、体等 和明暗、灰度(亮度)、色彩等 构成的&#xff0c;从现实世界中抽象出来的带有灰度、色彩及形状的图或形。 2、 一个计算机图形系统至少应具有 、 、输入、输出、 等基本功能。3、 常…

linux下运行yolo,Ubuntu下CPU/GPU模式YOLOv3代码运行

YOLO是近几年物体检测主要算法之一&#xff0c;2018年已发展到YOLOv3&#xff0c;是目前速度最快的物体检测算法&#xff0c;详细内容可查看YOLO主页。YOLO的主要优势在于基于纯C语言编写的DarkNet&#xff0c;可查看DarkNet主页&#xff0c;不需要其他依赖库&#xff0c;跨平台…

sqlyog设置自动补全_Visual Studio Code 最好的功能、插件和设置

Visual Studio Code 是由 Microsoft(微软) 发布的一个免费的&#xff0c;开源的跨平台文本编辑器。他们基于在线编辑 Visual Studio Online (代号为 “Monaco”)&#xff0c;并结合 GitHub 的 Electron 实现的一个跨平台编辑器。他们在为程序员创建一个快速且高效工作环境方面取…

ejb 示例 2018_Java EE EJB拦截器教程和示例

ejb 示例 2018在此示例中&#xff0c;我们将看到如何在EJB中使用拦截器并使用简单的Web应用程序对其进行测试。 1.简介 顾名思义&#xff0c;当您想拦截对EJB方法的调用时&#xff0c;将使用拦截器。 如果为Bean声明一个拦截器&#xff0c;则每次调用该Bean的方法时&#xff0…

linux怎么使用串口线,如何在Linux下使用USB转串口线,鼎力告诉您

亲爱的朋友&#xff0c;如果您使用的Linux的系统&#xff0c;应该怎么来使用我们的鼎力的USB转串口线呢&#xff1f;下面就来告诉您吧&#xff01;用Linux&#xff0c;不需要另外安装USB转串口驱动!前提是你要先安装minicom输入命令&#xff1a;dmesg| grep usb&#xff0c;看到…

stlink 升级固件以后失败_STM32固件升级的一点经验

上面理论实践当初花了3天时间弄完的&#xff0c;但是&#xff0c;当你真正做项目的时候&#xff0c;你会发现&#xff0c;只有上面的这些知识还不够&#xff0c;还有更多的细节要去处理&#xff1a;APP程序怎么跳转到BootLoader程序&#xff1f;APP程序和BootLoader之间是否会互…

linux搭建Django环境,Linux (ubuntu 12.04)下搭建Python Django环境

1. 检查python是否安装&#xff1a;直接在shell里输入python&#xff0c;如果已经安装了python&#xff0c;即可进入python bash&#xff0c;并看到版本号(如Python 2.7.3)——在ubuntu中python应该是已经默认安装好了2. 安装Django:sudopythonsetup.pyinstall检查Django是否安…

comsol分析时总位移代表什么_超弹性材料模型的压缩分析

为了表征超弹性材料&#xff0c;需要进行各种测试获取实验数据&#xff0c;包括承受单轴拉伸和压缩、双轴拉伸和压缩以及扭转测试。今天&#xff0c;我们向大家介绍如何使用通过单轴和双轴测试获得的拉伸和压缩测试数据&#xff0c;模拟由弹性泡沫材料制成的球体的压缩。通过案…

linux函数计时,Linux 中的计时——gettimeofday函数

&#xff11;.使用C语言进行计时在用户空间中可以使用C语言函数gettimeofday 得到时间&#xff0c;它的调用格式是&#xff1a;#include int gettimeofday(struct timeval *tv, struct timezone *tz);int settimeofday(const struct timeval *tv , const struct timezone *tz);…