mysql如果索引为uid间隙锁_MySQL-浅析间隙锁
MySQL 锁有哪些
从类型上来看,可以分为共享锁、排它锁
从范围来看,可以分为表锁、行锁,间隙锁、页锁等。
其中表锁中又有意向锁。
以上锁根据存储引擎不同,生效的锁也不同。
什么是间隙锁
我们首先先定义下关于下面描述的前提场景,首先是基于InnoDB存储引擎,Repeatable Read 隔离级别下的。从名字我们可以猜测出,间隙锁,锁定的是某块间隙,但是锁定的是那块间隙呢?什么场景会触发间隙锁呢?网上有很多关于间隙锁的原理讲解,但有的描述不严谨,下面就带着疑问,跟随一起一步步验证下吧。(PS:下面描述的内容不全是间隙锁,当时验证的时候出了一些自认为很有意思的问题,就记了下来和大家分享,知晓的朋友请自动忽略)
间隙锁锁定范围
首先定义如下表
CREATE TABLE `gap_lock` (
id bigint(20) NOT NULL,
number int(11) NOT NULL,
PRIMARY KEY (id) USING BTREE,
INDEX idx_number(number) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
插入相应的数据
INSERT INTO `gap_lock`(`id`, `number`) VALUES (1, 1);
INSERT INTO `gap_lock`(`id`, `number`) VALUES (3, 3);
INSERT INTO `gap_lock`(`id`, `number`) VALUES (5, 5);
INSERT INTO `gap_lock`(`id`, `number`) VALUES (8, 8);
锁定某行数据
select * from `gap_lock` where number = 3 for update;
image-20190423152444434.png
此时,我们开启一个新的会话,验证下面的sql
insert into `gap_lock` values(2,2);#阻塞
insert into `gap_lock` values(4,4);#阻塞
insert into `gap_lock` values(6,5);#非阻塞
insert into `gap_lock` values(0,1);#非阻塞
从上面的执行SQL情况可以看出,间隙锁锁定范围是number 数值(1,3)和 (3,5),开区间。我们再执行下下面的sql
insert into `gap_lock` values(2,1);#阻塞
纳尼,不是开区间么?不包含number等于3和5 么?难道是不单单锁定二级索引number,还锁定了主键索引的范围,整个锁定范围ID是(1,3)和(3,5),number范围是(1,3)和(3,5)?如果是这样的话,那么怎么的一个判断逻辑呢?是如下的判断逻辑么
boolean idLocked = (id > 1 && id < 3) || (id > 3 && id < 5);
boolean numberLocked = (number > 1 && number < 3) || (number > 3 && number < 5);
if(idLocked && numberLocked){
return true;
}
我们继续验证
insert into `gap_lock` values(2,6);#非阻塞
123.png
???首先可以确定的是上面的假想有问题,而且此时会有疑问,为什么(2,6)在第四行,不是默认按照id升序排序么,怎么会按照number排序,难道还和排序有关,此时一脸懵逼.jpg。我们继续验证
insert into `gap_lock` values(6,1);#阻塞
234.png
(6,1)在第二行,确实出现在我们以前画的锁定的间隙范围内,看来首要问题就是要解决下排序问题了,搞清楚排序问题,应该问题就迎刃而解了。
我们来看看查询的执行计划
explain select * from `gap_lock`;
345.png
通过执行计划,发现原来是使用了覆盖索引机制,怪不得排序不是按照主键进行的排序。我们回顾下innodb的索引结构。
456.png
树的内节点存储索引的key,叶子节点存储key和具体的数据信息,如果是二级索引,data是记录的主键值,如果是主键索引的话,data的是包含事务ID、回滚ID、版本号以及行数据信息等。
由于IO操作耗时,提高性能的可以通过减少磁盘的IO次数,目前这张表刚好只有两个字段,二级索引number其实可以覆盖所有的行数据信息,读取number索引可以达到查询全部字段的效果,相对来说,二级索引相较于主键索引存储更密集,磁盘IO读取次数更少。
知晓了排序的问题,那么间隙锁锁定范围就突然清晰了
467.png
在number这个索引上,排序是如上图,优先按照number进行排序,如果number相同,则按照id排序,大致判断逻辑如下
Node lockNode = new Node(3,3);
Node preNode = lockNode.pre;//(1,1)
Node nextNode = lockNode.next;//(5,5);
/**
* 校验是否被间隙锁锁住,不能执行插入操作
* @param node 待插入的索引节点
* @return true 表示不允许执行插入操作,false表示可以执行插入操作。
**/
public boolean checkGapLock(Node node){
//锁定的行是最后一行
if(nextNode == null){
if(node.key > preNode.key){
return true;
}else if(node.key == preNode.key && node.val > preNode.val){
return true;
}
return false;
}
//锁定的是中间某行(该索引节点不一定存在)
if(node.key > preNode.key && node.key < nextNode.key){
return true;
}else if(node.key == preNode.key && node.val > preNode.val){
return true;
}else if(node.key == nextNode.key && node.val < next.val){
return true;
}else{
return false;
}
}
怎样触发间隙锁的呢?
网上很多描述,例如select * from table where index = xx for update,又或者删除某条不存在的记录等。
二级索引&非唯一索引 ,如果某个叶子节点(若不存在则假设它存在)被添加了排它锁,那么就会在该叶子节点周围添加间隙锁,如果刚好其它会话要在间隙锁范围内创建索引,那么则会被挂起。
主键索引& 唯一索引,如果要添加排它锁的节点存在,不会触发间隙锁,如果不存在,则触发间隙锁。
为什么主键索引或者唯一索引与普通的索引在间隙锁上的机制有差别呢?我们先来看看什么是幻读和不可重复读。
幻读和不可重复读从结果来看,都是针对一个事务中,多次读取的结果与目标结果不一致。从解决的目的上,是区分不了幻读和不可重复读的。那么从范围上去划分。
从范围上区划分,分为指定行多次读取结果不一致,和范围读取结果不一致。
指定行多次读取,为了解决结果不一致的问题,最简单的办法是加锁(悲观锁)和多版本控制(MVCC)(乐观锁)来实现。我(个人理解,可能不正确)称指定行多次读取结果不一致,叫做不可重复读。
范围多次读取,这样简单的添加行锁是不可能解决多次读取结果不一致的问题,因此需要在范围添加锁。我(个人理解,可能不正确)称范围多次读取结果不一致的问题,叫做幻读。
这也就可以解释,为什么唯一索引、或者主键索引,当要删除、修改一个不存在的行时,触发了间隙锁,锁定了某个范围,而记录存在时,只是触发了行锁(可以明确指定行)。从索引的概念来讲,可以明确锁定某个索引的,且该索引值不会出现重复的,就是不可重复读的问题,不能明确锁定某个索引、或者某个索引值是可重复的,那么就会触发间隙锁,也是幻读的问题。
思考
假设我们又新增了一个字段val,该字段也添加了索引(非唯一索引),如果执行下面的语句会触发间隙锁么?如果触发,是number索引添加间隙锁,还是val索引添加间隙锁,还是都添加呢?
select * from `gap_lock` where number = 3 and val = 3 for update;
mysql如果索引为uid间隙锁_MySQL-浅析间隙锁相关推荐
- mysql如果索引为uid间隙锁_mysql 开发进阶篇系列 10 锁问题 (使用“索引或间隙锁”的锁冲突)...
1.使用"相同索引键值"的冲突 由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的.设计时要注意 例 ...
- mysql innodb 间隙锁_Mysql innodb 间隙锁
前段时间系统老是出现insert死锁,很是纠结.经过排查发现是间隙锁!间隙锁是innodb中行锁的一种, 但是这种锁锁住的却不止一行数据,他锁住的是多行,是一个数据范围.间隙锁的主要作用是为了防止出现 ...
- mysql表级锁和行级锁_MySQL表级锁和行级锁
一:概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking ...
- mysql 表级锁_MySQL行级锁和表级锁
锁定用于确保事务完整性和数据库一致性. 锁定可以防止用户读取其他用户正在更改的数据,并防止多个用户同时更改相同的数据. 如果不使用锁定,数据库中的数据可能在逻辑上变得不正确,而针对这些数据进行查询可能 ...
- mysql a锁_MYSQL中的锁
前言 刚开始接触MYSQL,对其锁机制并不了解,在项目里面,针对死锁以及锁竞争,约定了两条规则. 对涉及多个业务表的更新,要遵守一定的顺序,如按照TABLE-A,TABLE-B,TABLE-C的次序 ...
- mysql聚集索引可以多列吗_MySQL使用单列索引和多列索引
讨论MySQL选择索引时单列单列索引和多列索引使用,以及多列索引的最左前缀原则. 1. 单列索引 在性能优化过程中,选择在哪些列上创建索引是最重要的步骤之一.可以考虑使用索引的主要有两种类型的列:在W ...
- mysql默认乐观锁悲观锁_MySQL中悲观锁和乐观锁到底是什么?-阿里云开发者社区...
索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁. 行锁就是按 ...
- mysql中的乐观锁_MySQL中悲观锁和乐观锁到底是什么?
索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁.行锁就是按照 ...
- mysql s x锁_mysql 的S 锁和X锁的区别
共享锁和排它锁 MySQL的锁系统:shared lock和exclusive lock(共享锁和排他锁,也叫读锁和写锁,即read lock和write lock) 读锁是共享的,或者说是相互不阻塞 ...
- mysql普通查询排他锁_MySql 共享锁 排他锁
行级锁是 MySQL 中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突,行级锁分为共享锁和排他锁两种. 共享锁(Share Lock) 共享锁又称读锁,是读取操作创建的锁.其他用户可以并发读取 ...
最新文章
- xamarin 学习笔记02- IOS Simulator for windows 安装
- linux shell编程学习笔记(9)正则表达式
- 新概念0810:我理解的经济内循环
- 云原生数据库 2.0:一站式全链路数据管理与服务
- 深入理解connect by
- 接口管理平台YApi
- 最全面的AndroidStudio配置指南总结-包括护眼模式
- centos7按报错dracut
- Nexus3功能介绍
- Mirth Connect的简单使用
- iOS利用HealthKit获取健康里的步数和睡眠时间
- 案例推荐《微博:随时随地迎战大流量》
- STM32—建立工程模板
- R语者小case之——从KEGG原始网页批量生成通路的基因表格
- 微服务拆分策略和原则
- mi4a android tv,小米电视4A精简系统教程
- 迅为iTop4412精英板运行QT程序触摸/鼠标失灵
- 难道没有GPHONE??
- H5+CSS实现三级菜单(包括水平、垂直菜单和网页架构)
- 黎曼猜想有可能证明哥德巴赫猜想