MySQL行锁、表锁&间隙锁

目录

表级锁&行级锁

排它锁和共享锁

共享锁(Shared),又称为S锁,读锁

排它锁(Exclusive),又称为X锁,写锁

InnoDB行级锁

行级锁

间隙锁(gap lock)(串行口隔离级别怎么解决幻读问题?)

幻读场景:

 第一类条件:范围查询

 第二类条件:等值查询

 间隙锁和next-key lock:

原则:

优化:

注意:

死锁:不同线程可以给同一个间隙加锁


事务隔离级别的实现原理:锁+MVCC

表级锁&行级锁

开销加锁是否出现死锁锁力度发生锁冲突的概率并发度
表级锁(对整张表加锁)不会
行级锁(对某行记录加锁)最小最低

注:<1>对于InnoDB,绝大部分情况应该使用行锁

<2>使用表锁中,表比较大,事务需要更新全部或大部分数据

<3>事务涉及到多个表,比较复杂,可能引起死锁,造成大量的事务回滚

排它锁和共享锁

共享锁(Shared),又称为S锁,读锁

共享锁锁定的资源可以被其他用户读取,但不能修改

在进行SELECT的时候,会将对象进行共享锁锁定,当数据读取完毕之后,就会释放共享锁,这样就可以保证数据在读取时不被修改。

排它锁(Exclusive),又称为X锁,写锁

排它锁锁定的数据只允许进行锁定操作的事务使用,其他事务无法对已锁定的数据进行查询或修改

X锁和S锁之间有以下的关系:SS(读-读)可以兼容的,SX(读-写)、XX(写-写)之间是互斥的

<1>一个事务对数据对象O加了S锁,可以对O进行读取操作,但不能进行更新操作。加锁期间其他事务能对O加S锁但不能加X锁

<2>一个事务对数据对象O加了X锁,就可以对O进行读取和更新。加速期间其他事务不能对O加任何锁。

//对某一行加上共享锁
select uid from student where uid=1 lock in share mode; 
//对某个数据行上添加排它锁
select uid from student where uid=1 for update;

InnoDB行级锁

InnoDB存储引擎支持事务处理,表支持行级锁定,并发能力更好

行级锁

<1>InnoDB的行锁是通过给在索引上的索引项加锁来实现的,是给索引在加锁,并不是给单纯表的行记录在加锁;索引若过滤条件没有索引的话,使用的就是表锁,而不是行锁!!!

<2>由于InnoDB的行锁实现是针对索引字段添加的锁,不是针对行记录加的锁,因此虽然访问的是InnoDB引擎下表的不同行,但若使用相同的索引字段作为过滤条件,依然会发生锁冲突,只能串行进行,不能并发进行

<3>即使SQL中使用了索引,但是经过MySQL的优化器后,若认为全表扫描比使用索引效率更高,此时会放弃使用索引,因此也不会使用行锁,而是使用表锁,比如对一些很小的表,MySQL就不会去使用索引。

间隙锁(gap lock)(串行口隔离级别怎么解决幻读问题?

间隙锁是专门用于解决幻读这种问题的锁,它锁的是行与行之间的间隙,能够阻塞新插入的操作

间隙锁的引入也带来了一些新的问题,比如:降低并发度,可能导致死锁。

注意:读读不互斥,读写/写读/写写实互斥的,但是间隙锁之间是不冲突的,间隙锁会阻塞插入操作。另外,间隙锁在可重复读级别下才是有效的。

幻读场景:

 

 第一类条件:范围查询

 注:当使用索引时,经过MySQL优化器,认为全盘扫描比使用索引效率高,则变成表级锁,当前只能插入表头之前或表尾之后。

 第二类条件:等值查询

引入上图场景所用表进行解读

注:若age是主键索引和唯一索引(值是不允许重复的),那就只有行锁

 间隙锁和next-key lock:

行锁和间隙锁合称为next-key lock,这个锁是左开右闭的区。

原则:

原则1:加锁的基本单位是next-key lock,next-key lock是前开后闭区间。

原则2:查找过程中访问到的对象才会加锁

优化:

优化1:索引上的等值查询,给主键索引,唯一索引加锁的时候,next-key lock退化为行锁,若不存在这个索引,退化为间隙锁。

优化2:索引上的等值查询,向后遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。

注意:

1.非唯一索引的范围查询:范围查询都会访问到不满足条件的第一个值,并且不会执行上述的两个优化。唯一索引的范围查询依旧会执行上述的优化。

2.delete语句和查询的加锁方式相同

3.limit语句,遍历到满足条件的n条数据后,之后不再加next-key lock

死锁:不同线程可以给同一个间隙加锁

只有我这个线程可以操控这个间隙,其他线程不能使用,加锁时不会检测是否冲突的,但是如果两个都给同一个间隙上锁,之后两个线程都没办法在这个间隙上更新数据啦,都会陷入等待另一个线程的间隙锁释放,也就是死锁。

若使用读提交隔离级别(read-committed),那么只加行锁,不加间隙锁,语句执行过程中加上的行锁,在语句执行完成后,就要把“不满足条件的行”上的行锁直接释放啦,不需要等到事务提交才释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值