幻读

一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。

当前读和快照度

当前读指的是select for update 或者select in share mode,在更新之前必须先查询当前的值,因此叫做当前读。
快照读指的是,在语句执行之前或者在事务开始的时候会创建一个视图,后面的读都是基于这个视图的,不会再去查询最新的值。

间隙锁Gap Lock

image.png
锁的是两个值之间的空隙。间隙锁和间隙锁之间不会冲突。(间隙锁默认为开区间)
间隙锁和行锁合称next-key lock,是一个前开后闭区间。

1.对主键或唯一索引,如果当前读时,where条件全部精确命中(=或者in),这种场景本身就不会出现幻读,所以只会加行记录锁。   2.没有索引的列,当前读操作时,会加全表gap锁,生产环境要注意。   3.非唯一索引列,如果where条件部分命中(>、<、like等)或者全未命中,则会加附近Gap间隙锁。例如,某表数据如下,非唯一索引2,6,9,9,11,15。如下语句要操作非唯一索引列9的数据,gap锁将会锁定的列是(6,11),gap锁和record共同组成的next-key锁将会锁定的列是(6,11] ,该区间内无法插入数据。

间隙锁容易导致死锁

image.png
session A 执行 select … for update 语句,由于 id=9 这一行并不存在,因此会加上间隙锁 (5,10);
session B 执行 select … for update 语句,同样会加上间隙锁 (5,10),间隙锁之间不会冲突,因此这个语句可以执行成功;
session B 试图插入一行 (9,9,9),被 session A 的间隙锁挡住了,只好进入等待;session A 试图插入一行 (9,9,9),被 session B 的间隙锁挡住了。
至此,两个 session 进入互相等待状态,形成死锁。当然,InnoDB 的死锁检测马上就发现了这对死锁关系,让 session A 的 insert 语句报错返回了。