mysql幻读与加锁规则
说明,在mysql的可重复读级别下,是很难模拟出幻读的情况的。幻读是指在一个事务的多次查询时,查到了之前没有出现过的行(指新增的行)。由于一般的select查询是“快照读”,自然是不可能出现这种事情的,所以幻读指的是“当前读”(例如 select *** for update)。
有一表m,有三列如下。
字段 | 说明 |
---|---|
id | 主键 |
c | 普通索引 |
d | 普通列 |
初始数据有6行,分别是(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25)
案例1
- sessionA对c处于 (0,5]和(5,10]之间的数据记录加上了next-key锁。
- sessionB的前3条update语句都可以执行成功,但是第4条update语句会阻塞。因为第四条语句可以理解为 要在索引c上插入一个(c=5,id=0)这一行,但是其落在(0,5]和(5,10]之间,所以阻塞。
注意,锁是加在索引上的。
案例2
- 因为id=9的记录不存在,所以sessionA加上了间隙锁(5,10)
- 因为间隙锁之间不会发生冲突,所以sessionB的select *** for update也可以执行成功
- 因为sessionA的间隙锁,所以sessionB的insert插入会阻塞
- 因为sessionB的间隙锁,所以sessionA的insert插入会阻塞
mysql会发现死锁的存在,sessionA的insert语句会报错返回。
加锁的几个规则,如下:
- 访问到的对象那个才会加锁,比如
select id from m where c=5 lock in share mode;
因为查询使用到了覆盖索引
,所以主键索引上不会加锁。也就是锁,另外一个事务执行update m set d =5 where id =5
是不会阻塞的。