Innodb存储引擎的锁机制(三)--怎么利用锁解决并发事务带来的问题?

1怎么利用锁解决并发事务带来的问题?

1. 解决脏读:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-773aer4F-1583994670265)(6DDB19830F174FCBACD7C0042F618AAD)]

解释: 事务B在更新数据时,加上了X锁,则其他事务就不能读取和操作这条数据,事务A的select是不能直接从原表中查的,这时事务A会从快照中查询,因为快照中的数据是事务B 更新前保留的原始数据,所以事务A查到的结果不是18,而是16。

2. 解决不可重复读

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fr25QOWR-1583994670267)(14EEBE06D28245D4B3EA315104124B9A)]

解释: 事务A第一次查询的时候加了一把共享锁,此时其他事务只能读取,不能操作数据,所以事务B的update操作会等待事务A的锁释放了才能执行,所以事务A第二次查询的时候还是读取到16

3. 解决幻读

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8DZI0fs-1583994670267)(E4B943374BB84B49B89B6B1C0A25165E)]

Innodb在默认隔离级别RR级别是,select 索引范围查找会加上临键锁,临键锁能解决幻读问题,详见临键锁

4. 死锁

多个并发事务(2个或者以上);
每个事务都持有锁(或者是已经在等待锁);
每个事务都需要再继续持有锁;
事务之间产生加锁的循环等待,形成死锁。

4.1. 案例:

BEGIN;
update users set lastUpdate = NOW() where id =1; --A: 拿到users表的id=1这行的排他锁,下一步想拿到t2表id=1的排他锁,需要等B释放锁
update t2 set `name`='test' where id =1;

-- 其他会话

BEGIN;
update t2 set `name`='test' where id =1; --B: 拿到了t2表的id=1这行的排他锁,下一步想拿到users表id=1的排他锁,需要等A释放锁
update users set lastUpdate = NOW() where id =1;

上面的请求就出现了A等B 释放锁,B 等A释放锁。一直处于等待状态。可以通过kill连接id的方式解决。

4.2. 死锁的避免
1)类似的业务逻辑以固定的顺序访问表和行。
2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
4)降低隔离级别,如果业务允许,将隔离级别调低也是较好的选择
5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添 加上锁(或者说是表锁)

参考书籍:高性能MySQL(第3版)、高性能mysql

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值