问题大纲
版本更新时间:
V1.0:2021.01.02
V2.0:2021.09.21
一、锁是什么?
1、锁作用?
答:为了让并发线程正确地访问共享资源。
二、锁分类及具体应用
1、幻读是什么?
答:幻读指一个事务两次查询同一个范围时,后一次看到了前一次没看到的行。
注意:
1)可重复读隔离级别下,普通查询是快照读,不会看到别的事务插入的数据。而幻读在“当前读”(能看到最新提交记录)下出现。
2)update的结果不能称为幻读,仅专指“新插入的行”。
追问1:幻读有什么问题?
1)语义一致性被破坏。行锁应该不准别的事务对锁住行进行读写操作,但新更新或插入到那行无法预防。
2)数据和日志在逻辑上的不一致性。
追问2:给所有的记录都加上锁,都阻止不了新插入的记录。那如何解决幻读呢?
答:幻读产生原因是,行锁只能锁住行,但新插入记录这个动作更新的是记录之间的“间隙”。为了解决幻读问题,InnoDB引入了间隙锁(Gap Lock)
-
间隙锁,锁的是两个值之间的空隙,给范围加锁。比如,插入6个记录,就产生7个间隙。
间隙锁与读写锁不太一样,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作,间隙锁之间不存在冲突关系。
间隙锁和行锁合称为next-key lock,每个next-key lock是前开后闭区间。如果把select * from t for update把整个表所有记录锁起来,就形成了7个next-key lock,分别是(-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。
注:这里把间隙锁记为开区间,把 next-key lock 记为前开后闭区间。
追问3:间隙锁会遇到死锁吗?缺点是什么?
答:会,下面例子会死锁。
缺点:间隙锁引入,可能导致同样语句锁住更大范围,影响并发度。
追问4:间隙锁的缺点有什么办法避免吗?
答:间隙锁是在可重复读隔离级别下才会生效的。所以,如果把隔离级别设置为读提交,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row。
追问5:这又会带来什么问题?
答:根据具体业务需求进行分析,有待进一步理解与深入。……
三、锁如何设计与实现?
1、核心需要合理设置访问资源的规则。
2、锁实现?
3、手里同时有两个任务,如何处理?
四、参考
1、MongoDB 存储引擎:WiredTiger和In-Memory
2、《深入浅出MySQL》–第7章 表类型(存储引擎)的选择
3、乐观锁、悲观锁,这一篇就够了!
4、面试必备之乐观锁与悲观锁
5、【BAT面试题系列】面试官:你了解乐观锁和悲观锁吗?
6、死锁四个必要条件及死锁的预防、检测、避免、解除
7、死锁的产生、防止、避免、检测和解除
8、20 | 幻读是什么,幻读有什么问题?
9、MySQL优化(1)--------常用的优化步骤
10、SQL查询优化的步骤