谈谈你对间隙锁的理解

间隙锁

简介

间隙锁是对数据库表一定范围上的加锁,它能和行锁组成next-key lock解决在可重复读事务隔离级别下产生的幻读问题。幻读就是一个事务在进行范围查询的时候,前后查询的结果不一样。

原则

来记录下MySQL在可重复读事务隔离级别下加锁的规则:

  1. 加锁的基本单位是next-key lock,它是前开后闭的原则。
  2. 查询过程中访问的对象会增加锁
  3. 索引上的等值查询–给唯一索引加锁的时候,next-key lock会升级为行锁
  4. 索引上的等值查询–向右遍历时,最后一个值不满足查询要求的话,会将next-key lock退化为间隙锁
  5. 唯一索引在范围查询时会访问到不满足条件的第一个值为止

通过案例解释上面的原则

先声明一下,下面的这些案例都是基于可重复读事务隔离级别的

数据介绍

假设现在我有几条数据:

步骤id(唯一索引)c(普通索引)d(无索引)
1111
2555
3101010
4151515
以上数据为了解决幻读的问题,更新的时候,不只是对上述的每行数据都加行锁,并且对于中间的取值范围也加了锁,这个锁就是我们所说的间隙锁。这样以来,行锁+间隙锁组成next-key lock,这个锁的信息就是:(-°,1],(1,5],(5,10],(10,15],(15,+supernum],(其中,supernum是MySQL数据库维护的最大的值,来保证next-key lock是左开右闭的原则)

案例

案例1:间隙锁简单案例
步骤事务A事务B
1begin;
select * from table where id = 3 for update
2-insert into tabble value(4,4,4)
block;
3commit;-
这个就是一个简单的案例,我们来分析下他的流程:
  • 当有上面这两个事务时,事务A的操作会对数据库增加一个(1,5]范围的锁,这时候事务B是不能进行插入数据的,处于阻塞状态
案例2:间隙锁死锁问题
步骤事务A事务B
1begin;
select * from table where id = 3 for update
2-begin;
select * from table where id = 4 for update
3-insert into table value(2,2,2)
block;
3nsert into table value(2,2,2)
block;
-
不同于写锁是互斥的,间隙锁不是互斥的,两个事务都能获取到这个间隙锁,但是获得这个间隙锁之后,是不允许其他事务对这个间隙锁进行DDL操作的,所以两者就进入到死锁状态
案例3:等值查询–唯一索引
步骤事务A事务B事务C
1begin;
update table set d=d+1 where id = 7
--
2-insert into table value(8,8,8)
block;
-
3--update table set d=d+1 where id=10
1、先来看看MySQL会给数据库生成什么范围的锁:(5,10]
2、我们根据上面的原则四,我们看到这个范围最后一个值10与我们要查的id=7不相等,就会将这个next-key lock退化为间隙锁(5,10);
3、所以就可以解释事务B进行的插入操作是阻塞的,而事务C的操作是不阻塞的了。
案例4:等值查询–普通索引
步骤事务A事务B事务C
1begin;
select id from table where c=5 lock in share mode
--
2-update table set d=d+1 where id=5-
3--insert into table values(7,7,7)
block;
1、先来看看MySQL会给数据库生成什么范围的锁:(0,5],(5,10]
2、由于查询是等值查询,并且最后一个值不满足查询要求,故退化为间隙锁(5,10)
3、事务B能正常执行不阻塞的原因就是,事务A走的是覆盖索引并没有对主键索引加锁,所以B能正常执行
4、事务C插入的信息是7,在(5,10)之间,故会阻塞。
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Promise是一种用于处理异步操作的JavaScript对象。它可以将异步操作封装成一个Promise实例,通过链式调用then()方法来处理操作的结果。Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当异步操作完成时,Promise会根据操作的结果改变自身的状态,并执行相应的回调函数。 Promise的优点之一是可以避免回调地狱,即多个嵌套的回调函数导致代码难以维护和理解。通过使用Promise,可以将异步操作的处理逻辑以链式调用的方式表达出来,使代码更加清晰和可读。 Promise提供了一些静态方法,如Promise.resolve()和Promise.reject(),用于将普通的值转换为Promise对象。Promise.resolve()方法返回一个立即成功的Promise对象,而Promise.reject()方法返回一个立即失败的Promise对象。 另外,Promise还提供了Promise.all()和Promise.race()方法。Promise.all()方法接收一个Promise数组,并在所有Promise都成功时返回一个包含所有结果的Promise对象,如果有一个Promise失败,则返回一个失败的Promise对象。而Promise.race()方法接收一个Promise数组,并返回最先解决(成功或失败)的Promise对象的结果。 总之,Promise是一种用于处理异步操作的强大工具,它可以提高代码的可读性和可维护性,并提供了一些静态方法来处理多个Promise对象的结果。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* *3* [对Promise的理解](https://blog.csdn.net/liyongchunscr/article/details/120762934)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值