大家好,我是 Snow Hide,作为《MySQL 实战》这个专栏的学员之一,这是我打卡的第 9 天,也是我第 53 次进行这种操作。
今天我温习了该专栏里叫《为什么我只改一行的语句,锁这么多?》、《答疑文章(二):用动态的观点看加锁的文章》。
关键词总结:两个加锁原则、两个加锁优化、等值查询间隙锁、非唯一索引等值锁、主键索引范围锁、非唯一索引范围锁、唯一索引范围锁 bug、非唯一索引上存在 “等值” 的例子、limit 语句加锁、一个死锁的例子、不等号条件里的等值查询、等值查询过程、怎么看死锁?、怎么看锁等待?、update 的例子。
所学总结:
两个加锁原则
- 原则 1:加锁基本单位是 next-key lock。它是前开后闭区间;
- 原则 2:查找过程中访问到的对象才加锁。
两个加锁优化
- 优化 1:索引等值查询,唯一索引加锁时 next-key lock 退化为行锁;
- 优化 2:索引等值查询,向右遍历且最后一个值不满足等值条件时,next-key lock 退化为间隙锁。
等值查询间隙锁
会话 A 根据一个值来查询时产生的加锁范围左侧为小于该值的值,右侧为大于该值的值。会话 B 往间隙插入间隙范围内的值是会被锁住的。会话 C 修改间隙右侧的大于会话 A 查询的值是可以的。
非唯一索引等值锁
lock in share mode 只锁覆盖索引。执行 for update 时系统会认为加下来要更新数据,因此会顺便给主键索引上满足条件的行加锁。
要用 lock in share mode 给行加锁避免数据被更新的话,必须的绕过覆盖索引的优化,查询字段中加入索引不存在的字段。
主键索引范围锁
首次会话 A 定位查找某个值对应的行时,是当作等值查询来片段的,而向右扫描到另一个值对应的行时,用的是范围查询判断。
非唯一索引范围锁
非唯一索引没有优化规则,不会蜕变为行锁。
唯一索引范围锁 bug
锁住的是大于范围右侧值的行,应该是 Bug。
非唯一索引上存在 “等值” 的例子
索引值相同但主键不同的情况下也会产生一个它们之间的锁范围,从而不会影响它们之外的其他行。
limit 语句加锁
在删除数据的时候尽量加 limit,可以控制删除数据的条数,让操作更安全,还可以减小加锁的范围。
一个死锁的例子
分析加锁规则时可以用 next-key lock 来分析。具体执行时要分成间隙锁和行锁来执行。
不等号条件里的等值查询
在执行过程中,通过树搜索的方式定位记录的时候,用的是 “等值查询” 的方法。
等值查询过程
锁是在执行过程中一个一个加上的,而不是一次性加上的。
怎么看死锁?
- 锁是一个个假的,要避免死锁,对同一组资源,按照尽量相同的顺序访问;
- 发生死锁时,for update 语句占有资源更多,回滚成本更大,所以 InnoDB 选择了回滚成本更小的 lock in share mode 语句,来回滚。
怎么看锁等待?
间隙其实是由其右边的记录定义的。
update 的例子
第一条更新语句在执行后上锁,第二条更新语句要更新的值处在第一条更新语句上锁的范围内,所以第二条更新语句会被阻塞。
末了
重新总结了一下文中提到的内容:可重复读隔离级别下的验证、可重复读隔离级别遵守两阶段锁协议、事务提交或回滚时才释放加锁的资源、next-key lock 是间隙锁加行锁、提交隔离级别外键场景的间隙锁相对比较复杂、语句执行过程中上行锁,执行完毕后释放不满足条件行的锁、读提交隔离级别的锁范围更小时间更短、用可重复读隔离级别最大限度地提升系统并行处理事务的能力。