细说Mysql间隙锁

1.什么是间隙锁?间隙锁是怎样产生的?

2.间隙锁有什么作用?

3.使用间隙锁有什么隐患?

一、间隙锁的基本概念

1.什么叫间隙锁

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。

2.间隙锁的产生

上面的文字很抽象,现在举个栗子,介绍间隙锁是怎么产生的:

假设有以下表t_student:(其中id为PK,name为非唯一索引)

idnamesexaddress
1zhaoyi0beijin
3sunsan1shanghai
4lisi0guangzhou
5zhouwu0shenzhen
6wuliu1hangzhou

这个时候我们发出一条这样的加锁sql语句:

select id,name from t_student where id > 0 and id < 5 for update;

这时候,我们命中的数据为以下着色部分:

idnamesexaddress
1zhaoyi0beijin
3sunsan1shanghai
4lisi0guangzhou
5zhouwu0shenzhen
6wuliu1hangzhou

细心的朋友可能就会发现,这里缺少了条id为2的记录,我们的重点就在这里。

select ... for update这条语句,是会对数据记录加锁的,这里因为命中了索引,加的是行锁。从数据记录来看,这里排它锁锁住数据是id为1、3和4的这3条数据。

但是,看看前面我们的介绍——对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁。

好了,我们这里,键值在条件范围但是不存在的记录,就是id为2的记录,这里会对id为2数据加上间隙锁。假设这时候如果有id=2的记录insert进来了,是要等到这个事务结束以后才会执行的

二、间隙锁的作用

总的来说,有2个作用:防止幻读和防止数据误删/改

1.防止幻读

假设有下面场景

时间事务A事务B
T1select count(1) from t_student where id > 1; 
T2 insert into t_student values(2,'qianer',1,'nanjing');
T3 commit;
T4select count(1) from t_student where id > 1; 
T5commit; 

如果没有间隙锁,事务A在T1和T4读到的结果是不一样的,有了间隙锁,读的就是一样的了

2.防止数据误删/改

这个作用比较重要,假设以下场景:

时间事务A事务B
T1delete from t_student where id < 4; 
T2 insert into t_student values(2,'qianer',1,'nanjing');
T3 commit;
T4commit; 

这种情况下,如果没有间隙锁,会出现的问题是:id为2的记录,刚加进去,就被删除了,这种情况有时候对业务,是致命性的打击。加了间隙锁之后,由于insert语句要等待事务A执行完之后释放锁,避免了这种情况

三.使用间隙锁的隐患

最大的隐患就是性能问题

前面提到,假设这时候如果有id=2的记录insert进来了,是要等到这个事务结束以后才会执行的,假设是这种场景  

时间事务A事务B
T1select * from t_student where id>1 and id < 100 for update; 
T2 insert into t_student values(2,'qianer',1,'nanjing');
T3update t_student set xxxx where id=xxx; 
T4update t_student set xxxx where id=xxx; 
T5update t_student set xxxx where id=xxx; 
T6 
T7commit; 

这种情况,对插入的性能就有很大影响了,必须等到事务结束才能进行插入,性能大打折扣

更有甚者,如果间隙锁出现死锁的情况下,会更隐晦,更难定位

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
05-31
在Oracle中,PL/SQL是一种编程语言,允许开发人员编写存储过程、函数和触发器等程序对象。这些程序对象可以使用变量存储数据,其中包括全局变量和局部变量。 全局变量是定义在包中的变量,可以在包中的任何过程或函数中使用。在包中定义变量的语法如下: ``` CREATE OR REPLACE PACKAGE package_name AS variable_name datatype; ... END package_name; ``` 在这个包中,变量名为`variable_name`,数据类型为`datatype`。这个变量可以在这个包中的任何过程或函数中使用。 局部变量是在过程或函数中定义的变量,它们的作用域只在这个过程或函数中。在过程或函数中定义变量的语法如下: ``` CREATE OR REPLACE PROCEDURE procedure_name AS variable_name datatype; ... BEGIN ... END procedure_name; ``` 在这个过程或函数中,变量名为`variable_name`,数据类型为`datatype`。这个变量只能在这个过程或函数中使用,不能在其他过程或函数中使用。 全局变量和局部变量都可以存储不同类型的数据,例如数字、字符、日期等。在使用变量之前,需要先声明变量的类型和名称。在程序执行过程中,可以对变量进行赋值、修改等操作。 需要注意的是,在使用全局变量时,需要注意多个程序对象可能会同时访问同一个全局变量,因此需要考虑并发访问的问题。在使用局部变量时,需要注意变量的作用域和生命周期,确保变量只在需要的时候才会分配内存空间,并在不需要时及时释放内存空间,以避免资源的浪费。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值