我们知道在MySQL中存在幻读的情况,也就是一个事务在读取某个范围内的记录时,发现了另一个事务在该范围内新增了记录(或者删除了记录),导致两次读取的记录数量不一致 , 进而产生了“幻觉”一般的现象 。也就是说 , 幻读是指在多个事务同时读取同一范围内的记录时所产生的矛盾现象 。
MySQL为了解决幻读一般采用快照读和间隙锁的方式,其中快照读在之前的文章已经多次提及,本篇文章重点介绍间隙锁 。
间隙锁意如其名,就是锁定符合条件但是实际不存在的记录,也就是一定的区间 , 防止其他事务在某个事务执行期间向该区间插入新的记录 。
为清楚梳理间隙锁的作用,我们在本文中使用的示例表如下:
CREATE TABLE `t` (`id` int(11) NOT NULL,`c` int(11) DEFAULT NULL,`d` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `c` (`c`)) ENGINE=InnoDB;insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);
在示例表中执行如下语句:
begin;select * from t where d=5 for update;commit;
语句中的select for update就是为了在查询时,对相关语句进行加锁,避免其他用户对该表进行插入、修改、删除等操作,造成表的不一致 。
d=5这一行对应主键为Id=5,执行select语句后改行会被加写锁,并在commit后释放 。但是由于d列没有索引 , 所以会被全表扫描,这时候真实的加锁逻辑为:
- 全表扫描一般指主键索引树扫描;
- 对于会不会被加锁:
RR级别下会加行锁+全表间隙锁(next-key lock是左开右闭 , 间隙锁是左开右开);
这里可以先记住这个逻辑,我们在下面的文章中会逐步开始介绍 。1 幻读1.1 幻读是什么注意,如下的结论都是假设存在,从而引入间隙锁的概念 。
如果没有间隙锁,只有行锁,即:上面的语句只会锁?。篿d=5的这一行数据,那么就会出现如下图所示的场景:
文章插图
for update在当前读可以理解为:MySQL认为for update已经给当前的行加了写锁 , 因此没有必要再进行快照读 , 但是这样会造成幻读的问题 。
如果没有间隙锁,就会出现如下的结果:
- Q1 只返回 id=5 这一行;
- 在 T2 时刻,session B 把 id=0 这一行的 d 值改成了 5,因此 T3 时刻 Q2 查出来的是 id=0 和 id=5 这两行;
- 在 T4 时刻,session C 又插入一行(1,1,5),因此 T5 时刻 Q3 查出来的是 id=0、id=1 和 id=5 的这三行 。
- 快照读:指的是在语句执行之前或者在事务开始的时候创建一个一致性视图 , 后面的读都是基于这个视图,不会再去查询最新的值;
- 当前读:指的是更新之前必须先查询当前的值,因此叫做当前读 , 比如说:select for update或者select in share mode;
SELECT ... FOR UPDATE 走的是IX锁(意向排它锁),即在符合条件的rows上都加了排它锁,其他session也就无法在这些记录上添加任何的S锁或X锁 。如果不存在一致性非锁定读的话,那么其他session是无法读取和修改这些记录的,但是innodb有非锁定读(快照读并不需要加锁) , for update之后并不会阻塞其他session的快照读取操作;
除了select ...lock in share mode和select ... for update这种显示加锁的查询操作 。通过对比,发现for update的加锁方式无非是比lock in share mode的方式多阻塞了select...lock in share mode的查询方式,并不会阻塞快照读
推荐阅读
- Vue 微前端开发的七大神器
- .NET Core的中间件来对Web API进行流量限制实现方法
- MySQL时间存储终极指南:选择最适合你的时间类型!
- 梅花的嫁接时间,红梅杏嫁接时间
- 事业编制的教师,退休金的待遇和职称有关系吗?
- 萝卜疙瘩汤的做法
- 明星减肥前后差异有多大?减肥是最好的整容,有人完全认不出
- 佘诗曼新剧才是御姐和奶狗的正确打开方式?网友喊金莎来抄作业
- vivonex的屏幕发声到底怎么样
- 苜蓿的功效与作用,苜蓿的主要成分是什么?