深入浅出,简述MySql中的各种锁

其实对于一个开发人员来说,对数据库的掌握并不需要这么深入。
但本人亲身经历,面试的时候来一句“请你说说什么是间隙锁,一瞬间将我排除在候选人名单外。
而我面试的仅仅是中级开发工程师,可见现在的内卷程度有多严重。

因此本文章整理了一番Mysql中各种锁的作用和原理,欢迎学习交流。
🍅你的关注和点赞对我很重要🍅

为什么需要锁?

我们知道Mysql数据库提供了4种隔离级别来预防我们操作数据的时候可能带来的并发事务问题
在这里插入图片描述
上面的图片相信每个人都烂熟于心了,Mysql默认的隔离级别就是RR(REPEATABLE READ),避免了脏读和不可重复读,我们一般也将这个隔离级别成为:可重复读。

当面试进行到这里,你自我感觉还很良好的时候,面试官突然问你:你知道数据库的隔离级别的原理是什么吗?

好,这个时候,数据库的概念就出来了。

下面会通过这个脑图的结构依次简绍:
在这里插入图片描述

1 对数据操作的类型划分

1.1 读锁(共享/S锁)

读锁也称共享锁,多个事务同时读取同一份数据,相互不会影响不会阻塞,数据安全。
给select语句加共享锁

Select * from test LOCK IN SHARE MODE;Select * from test FOR SHARE;

1.2 写锁(排他/X锁)

写锁也称排他锁,排他排他,顾名思义就是排挤他人。多个事务同时操作(有读有写或同时写)同一份数据,在一个事务还没完成(提交)前,它会阻断其他的事务,保证数据的安全性。
给select语句加排他锁

Select * from test FOR UPDATE;

update语句默认会加上排他锁
看到这里你会不会有点感觉了。脏读是不是就是通过排他锁解决的呢?

案例

有一张user表,其中有这样一行初始数据:
在这里插入图片描述
现在模拟两个事务对这行数据进行操作:

  • 事务1:
    查询user表,加排他锁
    在这里插入图片描述
  • 事务2:
    查询user表,加排他锁
    在这里插入图片描述

2 锁粒度划分

2.1 表锁

表锁这里我们不展开解释了。顾名思义就是每次加锁就把整张表给锁了,一杆子打死。
我们知道Mysql有两种引擎,InnoDB和MyIsam。我们常用的是InnoDB,因为MyIsam不支持事务,并且MyIsam只能表锁,不能行锁。 而InnoDB支持事务,并且可以同时支持表锁行锁

2.2 行锁

为了提高数据库的并发吞吐量,每次锁定的范围越小越好,但这样的话加锁的数量就会变多,在锁的管理上也是很消耗资源的一件事。
所以,什么时候用表锁,什么时候用行锁,需要我们结合实际情况来考虑。
这里我们就先详细了解下我们平时用的最多的行锁

2.2.1 记录锁

记录锁记录锁,顾名思义就是给某一条记录加锁。
对于记录锁而言,它也分为共享锁排他锁,功能参考1.1和1.2的描述。

案例

有一张user表,其中有这样一行初始数据:
在这里插入图片描述
现在模拟两个事务对这行数据进行操作:

  • 事务1:
    修改user表,把张三的年龄改为20,默认加记录锁(排他锁,行锁)
    在这里插入图片描述
  • 事务2:
    查询user表,加读锁
    在这里插入图片描述
2.2.2 间隙锁

间隙锁是面试种最常问到的东西,听名字感觉很高大上的,其实也是很简单的一个东西。
间隙锁是防止幻读而产生的一种锁,是加在某一条不存在的数据上的一个锁。
幻读就是事务A第一次读到8条数据,这时候事务B插入了一条,事务A这时第二次读,发现读出来9条数据。多出来的这一条我们成为幻影数据

案例

初始数据:
在这里插入图片描述

间隙锁的案例我就不截图来演示,用文字描述更易懂。

  1. 事务A查询id =8的数据,发现查不到数据,并加了读锁,未提交。
  2. 事务B现在要插入一个id为6或7或8或9的数据,不能插入。
  3. 事务A提交了事务。
  4. 事务B现在才插入成功。

很明显,解决了幻读的问题。那到底是什么原理呢?为什么事务B不能插入呢?

事务A查询了一个不存在数据,例如id=8的数据。那么就会产生间隙锁间隙锁的这个间隙就会是5——10,也就是当前查寻Id的前后两个数据,id为5和id为10之间不能插入任何数据。

如果事务A查询的id=15,那么根据间隙锁的原理,插入的数据id如果大于当前表最大的id,则不能插入。这里就是如果事务B要插入id大于10的数据就插入失败。

间隙锁的危害:间隙锁是有可能会造成死锁的问题。

2.2.3 临键锁

临键锁就是记录锁间隙锁的结合,把间隙两头的数据也加上记录锁
结合上面的例子,就是:
事务A查询一个id=8的数据,那么5——10区间就会加上间隙锁,不能插入数据。而5和10这两条数据也会加上记录锁,不能读写操作。

具体操作就是在事务A进行范围查询的时候,加上for update。

2.2.4 插入意向锁

回顾之前我们的间隙锁,被间隙锁锁定的数据是阻塞、等待。
如果现在有多个插入事务都阻塞了,那他们之间会生成一个内部锁:插入意向锁

如:

  1. 事务A查询id =8的数据,发现查不到数据,并加了读锁,未提交。(5-10之间产生间隙锁
  2. 事务B插入一个id为6的数据。阻塞。
  3. 事务C插入一个id为7的数据。阻塞。
  4. 事务B,C之间就会产生一个插入意向锁。如果B、C插入的数据不冲突,那待事务A释放后,B,C就会依次插入成功。

3 锁态度划分

3.1 悲观锁

每次一个线程进来操作数据的时候,总会觉得有其他线程会来同时操作,所以我一来就加锁,其他的线程全部阻塞,直到我释放锁。

Mysql中的写锁(for update)就是悲观锁。
这种锁安全性高,但吞吐量低,对数据库性能消耗大,属于数据库层面的锁,适用于写多于读的场景。

3.2 乐观锁

每次一个线程进来操作数据的时候,不会觉得有其他线程会来同时操作,不加锁,但是会在操作之前先判断一下当前的数据没有没被其他线程修改过。一般通过一个版本号字段来判断。

这种锁吞吐量高,属于代码层面的锁。适用于读多于写的场景。

4 全局锁和死锁

4.1 全局锁

全局锁是对整个数据库进行加锁,让整个库都处于只读状态。 比如我们要备份数据库,以免其他人操作数据的时候我们可以加全局锁

Flush tables with read lock 

4.2 死锁

两个事务都持有对方需要的锁,并且都在等待对方释放,形成死锁。
在这里插入图片描述

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易柏州Innovation

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值