MySQL Update锁机制探究【转】
MySQL Update锁机制探究【转】
基于MySQL-8.0 with Innodb存储引擎,通过观察总结出UPDATE语句在各种情况下产生的锁,包括MDL锁、意向锁、行锁和间隙锁等。
测试环境
MySQL的Update语句会使用什么锁,取决于很多因素。本文基于MySQL-8.0 with Innodb存储引擎、可重复读隔离级别,具体版本和建表语句如下:
mysql> SELECT VERSION(); |
MDL读锁
MDL是指Metadata Locking,中文叫元数据锁,它是一个表级锁,用来保护表结构、触发器等并发访问的一致性。UPDATE语句产生的mdl读锁会阻塞表结构修改语句,例如:
- 事务1执行
UPDATE
语句:
mysql> BEGIN; |
- 事务2增加索引将被阻塞
mysql> alter table t1 add index index_age(`age`); |
意向写锁
意向锁也是一个表级锁,执行UPDATE
语句将会产生一个意向写锁。意向写锁只会阻塞LOCK TABLES xxx WRITE
语句,例如:
- 事务1执行
UPDATE
语句:
mysql> BEGIN; |
- 事务2获取表级写锁将被阻塞:
mysql> LOCK TABLES t1 WRITE; |
行级锁
行级锁包括:
- 记录锁 Record Lock
- 间隙锁 Gap Lock
- Next-Key Lock (记录锁和间隙锁的组合)
行级锁怎么加,会受到索引访问方式的影响,下面通过例子说明。
例1: 通过主键更新1条记录
UPDATE t1 SET age=222 WHERE id=5; |
这是一条最常见的UPDATE
语句,WHERE
条件使用主键索引来更新数据,加锁分为2种情况:
- id=5的记录存在,只会在id=5的主键索引加上一个行锁。
- id=5的记录不存在,会在主键索引上加上一个间隙锁。
间隙锁会阻止其它事务往这个间隙中插入数据。事务1执行UPDATE
不存在的记录:
mysql> BEGIN; |
表格中id列只有1、5、6,执行UPDATE ... WHERE id=2
将产生一个间隙锁(1, 5)
。例如插入id=3的记录将被阻塞:
mysql> INSERT into t1 (id,age) values (3, 80); |
例2: 通过主键更新一个范围
mysql> BEGIN; |
当WHERE
条件使用主键的范围来更新时,会同时加上行锁和间隙锁。例如表格中id列只有1、5、6,上述UPDATE
语句将会:
- 给id=5加上行锁
- 给id=6加上行锁
- 加上间隙锁(6, +∞)
插入(id=8)的记录将被间隙锁阻塞:
mysql> INSERT into t1 (id,age) values (8, 80); |
例3:通过无索引的字段更新
mysql> BEGIN; |
上面例子中,使用WHERE age=200条件,其中age字段没有索引,上述UPDATE语句将会锁住表格中的每一条记录和每个间隙,其它UPDATE、INSERT和DELETE语句都无法执行:
mysql> INSERT into t1 (id,age) values (8, 80); /* INSERT被阻塞 */ |
例4:通过唯一索引更新
表格中有2个辅助索引c和d,其中d是唯一索引。WHERE条件使用唯一索引更新记录:
mysql> BEGIN; |
当d=80记录存在时,将会:
- 给唯一索引d=80加上行锁(没有间隙锁)
- d=80对应记录的主键索引也会加上行锁(没有间隙锁)
- 没有用到的辅助索引c不受影响
当d=80的记录不存在时,将会在唯一索引d上加上间隙锁(与例1类似)。
使用唯一索引进行范围更新时:
mysql> UPDATE t1 SET age=111 WHERE d>70; |
与例2类似,将会:
- 给匹配到的主键索引记录加上行锁
- 给匹配到的唯一辅助索引记录加上行锁
- 给辅助索引加上间隙锁
例5:通过(非唯一)二级索引更新
mysql> UPDATE t1 SET age=111 WHERE c=300; |
表格中c字段有非唯一辅助索引,以上SQL将:
- 在辅助索引上加上Next-key锁
- 给WHERE条件匹配到的记录加上行锁
例6:多个条件更新
WHERE中包含多个条件时,加什么锁取决于使用了哪个索引,可以使用explain查看:
mysql> explain UPDATE t1 SET age=222 WHERE age=111 and c=100 and d=200; |
上面例子中WHERE条件中同时包含唯一索引d、非唯一索引c、无索引的字段age,从explain的结果中可以看出,最终使用了索引d,则加锁情况参考例4:通过唯一索引更新。
UPDATE语句加锁总结
UPDATE语句可能加的锁包括:
- MDL锁
- 意向锁
- 行锁
- 间隙锁
- Next-key Locking
参考 & 引用
本文转自东哥的个人博客