生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。

有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章 一文详解MySQL的锁机制

这篇主要通过小案例来对记录锁、间隙(gap)锁、临键(next-key)锁做一个更好的理解。

这里先给出结论,再来用实际例子证明

1、当使用唯一索引来等值查询的语句时, 如果这行数据存在,不产生间隙锁,而是记录锁。

2、当使用唯一索引来等值查询的语句时, 如果这行数据不存在,会产生间隙锁。

3、当使用唯一索引来范围查询的语句时,对于满足查询条件但不存在的数据产生间隙(gap)锁,如果查询存在的记录就会产生记录锁,加在一起就是临键锁(next-key)锁。

4、当使用普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;

5、在没有索引上不管是锁住单条,还是多条记录,都会产生表锁;

间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;

间隙的范围?

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

接下来我们开始来验证以上结论

一、数据和环境准备

1、创建表和数据

CREATE TABLE `t` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`age` int NOT NULL COMMENT '年龄',
`mobile` int DEFAULT NULL COMMENT '手机号',
`name` varchar(8) DEFAULT NULL COMMENT '名称',
PRIMARY KEY (`id`),
KEY `index_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

id为主键(唯一索引)、age是普通索引、mobile没有加索引

同时插入数据如下。

在进行测试之前,我们先来看看t表中存在的隐藏间隙:

(-∞, 1]

(1, 4]

(4, 7]

(7, +supernum]

(其中supernum是数据库维护的最大的值。为了保证间隙锁都是左开右闭原则。)

2、关闭事务默认提交

mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)

结果显示,autocommit 的值是 ON,表示系统开启自动提交模式。

在 MySQL 中,可以使用 SET autocommit 语句设置事务的自动提交模式,语法格式如下:

SET autocommit = 0|1|ON|OFF;

对取值的说明:

值为 0 和值为 OFF:关闭事务自动提交。如果关闭自动提交,用户将会一直处于某个事务中,只有提交或回滚后才会结束当前事务,重新开始一个新事务。

值为 1 和值为 ON:开启事务自动提交。如果开启自动提交,则每执行一条 SQL 语句,事务都会提交一次。

二、唯一索引示例

1、等值查询且数据存在示例

事务A 等值查询id=4,因为id是主键,同时是等值查询存在该记录,所以只会在id=4这条记录上加记录锁,不会加间隙锁。

事务B 等值查询id=5,没有锁冲突,所以查询正常,不会堵塞。(如果事务B 等值查询id=4,因为事务A加了记录锁,所以会堵塞)

2、等值查询且数据不存在示例

事务A 等值查询id=5,因为查询记录不存在,所以无法加记录锁,但这里会存在一个(5,7]的间隙锁。

事务B 插入一条id=6的数据,因为上面存在了(5,7]的间隙锁,所以会堵塞。

3、范围查询示例

事务A 范围查询id>4,那么这里就会存在一个(4,+supernum]的临键(next-key)锁。

事务B 插入一条id=6的数据,因为上面存在了(4,+supernum]的临键(next-key)锁,所以会堵塞。

如果 事务B 是更新 id=7 的记录,同样会堵塞。

三、普通索引示例

1、等值查询值

事务A 等值查询age=4,因为age是普通索引,所以会产生临键(next-key)锁(1,4]和(4,7],左开右闭原则。

事务B 插入一个id=6、age=6的数据,因为age值在上面临键锁,范围内,所以也会堵塞。

2、左开右闭原则

按照上面的例子,如果事务B插入一条 id=6,age=1 的数据会不会堵塞呢,因为按照左开右闭原则,上面的age=1是开的,所以正常应该是可以插入的。

但实际上你真是实践之后,你发现同样也会堵塞。

通过实践之后,会发现,所谓的左开右闭原则,跟主键id有关系。

上面的事务A 等值查询age=4,它的当前主键id=4,上一条记录主键id=1,下条记录主键id=7。

如果插入 id<1, age 在(1,7)范围内,是 左闭右开原则。即age=1能插入,age=7会堵塞。

如果插入 1<id<7,age 在(1,7)范围内,是 左闭右闭原则。即age=1会堵塞,age=7也会堵塞。

如果插入 id>7,age 在(1,7)范围内,是 左开右闭原则。即age=1会堵塞,age=7能插入。

有关等值查询值不存在、普通索引范围的示例这里就不举了,跟上面的差不多,都会产生间隙锁。

四、无索引示例

1、等值查询值

事务A 等值查询 mobile = 8888884,因为mobile是无索引的,所以这个for update,变成表级排他(X)锁。

事务B 因为事务A已经加了表级的排他锁,所以其它事务无法进行任何的增删改操作。

2、范围查询

事务A 等值查询 mobile > 8888884,因为mobile是无索引的,所以这个for update,变成表级排他(X)锁。

事务B 因为事务A已经加了表级的排他锁,所以其它事务无法进行任何的增删改操作。

MySQL记录锁、间隙锁、临键锁小案例演示的更多相关文章

  1. 【Mysql】表锁 行锁 记录锁 间隙锁

    Mysql中的锁 基于锁的属性分类:共享锁.排他锁. 基于锁的状态分类:意向共享锁.意向排它锁 根据锁的粒度分类:全局锁.页锁.表级锁.行锁(记录锁.间隙锁.和临键锁),实际上的锁就这些,上面两种分类 ...

  2. mysql 开发进阶篇系列 10 锁问题 (相同索引键值或同一行或间隙锁的冲突)

    1.使用相同索引键值的冲突 由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的.设计时要注意 例如:city表city_ ...

  3. mysql 锁问题 (相同索引键值或同一行或间隙锁的冲突)

    1.使用相同索引键值的冲突 由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的.设计时要注意 例如:city表city_ ...

  4. (10)MySQL进阶篇SQL优化(InnoDB锁-间隙锁)

    1.概述 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁:对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)&quo ...

  5. Mysql学习笔记-临键锁实验

    前言 昨天同事跟我聊到一个问题:InnoDB里面间隙锁锁住的数据可以update么?我们经常都说间隙锁是InnoDB在RR隔离级别下防止幻读的一种处理手段.它可以防止数据在间隙范围中insert数据, ...

  6. (9)MySQL进阶篇SQL优化(InnoDB锁-记录锁)

    1.概述 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点意味着:只有通过索引条件检索 ...

  7. MySQL数据库InnoDB存储引擎中的锁机制

    MySQL数据库InnoDB存储引擎中的锁机制    http://www.uml.org.cn/sjjm/201205302.asp   00 – 基本概念 当并发事务同时访问一个资源的时候,有可能 ...

  8. MySQL性能调优——锁定机制与锁优化分析

    针对多线程的并发访问,任何一个数据库都有其锁定机制,它的优劣直接关系着数据的一致完整性与数据库系统的高并发处理性能.锁定机制也因此成了各种数据库的核心技术之一.不同数据库存储引擎的锁定机制是不同的,本 ...

  9. MySQL学习(二)索引与锁 --- 2019年1月

    1.Order By 是怎么工作的 MySQL做排序是一个成本比较高的操作.MySQL会为每个线程分配一个 sort_buffer 内存用于排序,该内存大小为 sort_buffer_size. 全字 ...

随机推荐

  1. Part 32 AngularJS controller as syntax

    So far in this video series we have been using $scope to expose the members from the controller to t ...

  2. JDK的第三个LTS版本JDK17来了

    目录 简介 JDK17中的新特性 语言上的新特性 核心库的优化 支持新的平台 预览特性 其他改动 总结 简介 2021年9月JDK17发布了,JDK17是最新的一个LTS版本.所谓LTS版本就是可以得 ...

  3. AnnotationConfigApplicationContext(1)之初始化Scanner和Reader

    AnnotationConfigApplicationContext(1)初始化Scanner和Reader 我们以AnnotationConfigApplicationContext为起点来探究Sp ...

  4. 会话Cookie与session的关系

    在通常的使用中,我们只知道session信息是存放在服务器端,而cookie是存放在客户端.但服务器如何使用session和客户端之间进行通信,以及jsessionId是怎么回事,这并没有一个完整和正 ...

  5. [bzoj3317]First Knight

    建立方程后直接高斯消元,再把0的区间找出来计算,就可以过(因为实际上这样的复杂度是5次的,且常数小)(当然这样的复杂度看上去并不太好,考虑优化)可以发现最后一行的概率都可以用上一行来表示,那么代入上一 ...

  6. Codeforces 891E - Lust(生成函数)

    Codeforces 题面传送门 & 洛谷题面传送门 NaCly_Fish:<简单>的生成函数题 然鹅我连第一步都没 observe 出来 首先注意到如果我们按题意模拟那肯定是不方 ...

  7. Perl调用和管理外部文件中的变量(如软件和数据库配置文件)

    编写流程时,有一个好的习惯是将流程需要调用的软件.数据库等信息与脚本进行分离,这样可以统一管理流程的软件和数据库等信息,当它们路径改变或者升级的时候管理起来就很方便,而不需要去脚本中一个个寻找再修改. ...

  8. 【WEGO】GO注释可视化

    导入数据 BGI开发的一款web工具,用于可视化GO注释结果.自己平时不用,但要介绍给别人,简单记录下要点,避免每次授课前自己忘了又要摸索. 地址:http://wego.genomics.org.c ...

  9. 浅谈Facebook的服务器架构

    导读:毫无疑问,作为全球最领先的社交网络,Facebook的高性能集群系统承担了海量数据的处理,它的服务器架构一直为业界众人所关注.CSDN博主yanghehong在他自己最新的一篇博客< Fa ...

  10. HMS Core Discovery直播预告 | AI画质增强 ,开启超清视界

    [直播入口] B站华为开发者联盟:http://live.bilibili.com/22551651 4K.8K视频屡见不鲜,HD.FHD分辨率成小屏标配,当网络卡顿.视频自动切换到较低画质时,用户最 ...