MySQL:逃不掉的锁事,间隙锁( 三 )


那为什么RR级别不需要修改binlog_format呢:

  1. 间隙锁是可重复读级别下解决幻读的 , 同时解决了binlog和数据可能存在的不一致问题,即:binlog日志的写入顺序错误问题;
  2. 间隙锁解决了binlog的问题 , 而不是Binlog解决了间隙锁的问题;
  3. 读提交级别也有binlog执行顺序错误的问题 , 也没有间隙锁 , 因此 , 需要将binlog_format修改为row模式,来解决binlog可能带来的错误;
  4. binlog的row模式比statement要记录的更全面,每一行记录改变都记录下来,导致日志大,同时IO次数更多;
如果业务不需要可重复读场景,考虑在读提交下操作数据的锁范围更?。?挥屑湎端???这个选择是合理的 。
2.4 读提交和可重复读可重复读的场景举例,比如说:金融业务,财务需要统计过去一段时间内某些数据,需要反复根据某些条件查找,此时如果有新数据行插入,会导致统计时发生数据不一致的情况 , 此时需要使用可重复读的隔离级别 。
又比如说逻辑备份时,mysqldump备份线程会设置为可重复读,这样在导数据时就会启动一个事务 , 确保拿到一致性视图 。由于MVCC的支持 , 过程中数据可正常更新 。使用可重复读 , 是为了保证备份的数据都是那一时刻的最新数据,然后通过binlog再做后续的恢复即可 。
业务线程是读提交,备份线程是可重复读,同时存在两种事务隔离级别,是否会冲突?
答案是不会,因为不管是RC还是RR,都是MVCC支持,唯一不同在于生成快照的时间点不同,也就是能够看到的数据版本不同,所以并不影响 。备份完成后,恢复为RC即可 。
3 间隙锁的加锁规则加锁规则总结如下:
  1. 原则1:加锁的基本单位是next-key lock,是前开后闭;
  2. 原则2:查找过程中访问到的对象(索引)才会加锁;
  3. 优化1:索引上的等值查询,如果可以匹配到对应数据,则给唯一索引加锁 , next-key lock退化为行锁;如果匹配不到 , 按照原则2加锁;
  4. 优化2:索引上的等值查询 , 向右遍历时且最后一个值不满足等值条件时,next-key lock退化为间隙锁;
  5. 一个bug:唯一索引的范围查询会访问到不满足条件的第一个值为止;【该bug已经在MySQL8.0.18版本开始修复,但是也有提出实际上只修复了主键上的问题,唯一索引没有修复,需要验证】
原则2也就解释了:
  • 为什么未命中索引的查询要走全表扫描后导致全表加锁的原因;
  • 这里说的访问到的对象 , 是从底层结构来看待 , 而不是数据表的一行 。例如,普通索引和主键索引,如果访问到的是普通索引,而且通过索引覆盖并不需要回表查主键索引,那么主键索引上并不需要加任何的锁 , 因为并没有访问主键索引树上的对象 。
本节还是使用章节组开始的表进行说明 。
3.1 等值查询间隙锁
MySQL:逃不掉的锁事,间隙锁

文章插图
表中没有id=7的记录 , 因此:
  • 根据原则1,加锁单位为next-key lock,sessionA的加锁范围为:(5 , 10];由于是根据id进行检索,所以会锁住主键索引对象;
  • 根据优化2 , sessionA为等值查询,id=10不满足查询条件,退化为间隙锁,因此加锁的最终范围为(5,10);
因此,插入id=8的记录会被锁?。?等待sessionA锁释放,sessionC修改id=10这一行可以正常执行 。
3.2 非唯一索引等值锁
MySQL:逃不掉的锁事,间隙锁

文章插图
这个例子说明的就是原则2中的对象 。
注意:sessionA要给索引c=5加读锁,而且是索引c获取主键,实际上就是覆盖索引 , 不需要回表 。