整理下MySQL中的锁

1.锁的一些基础

锁是为了保护并发场景中临界资源,保证其有序变更。锁的粒度越粗,锁住的范围越大,并发度越低。

2.本文中主要探讨常用的一些锁:行锁、间隙锁、next-key lock、表级锁、MDL。

3.行锁

分为两类,共享锁S,排他锁X,对同一行数据而言,S可以兼容S,X不能兼容其他锁。

意向锁:对小粒度数据加锁前,一般对大粒度数据加意向锁。例如,对一行记录加S,对该行记录所在的表加IS。意向锁和行锁之间的兼容性很容易推理。

为什么要有意向锁?一个表中已经有了行锁的时候,此时想要加另一个行锁,先判断和意向锁是否冲突,如果冲突,就不必对每一行的行锁进行扫描了。

4.两种常见的涉及一致性以及锁的写法

select ... for update:对读取的该行加X锁。在rr级别下,被锁住的行也是可以读的。

select ... for share mode:对读取的该行加S锁。

5.主键自增与锁

AUTO-INC  locking,不等待事务完成,完成对自增长id插入的sql语句后就释放,增加并发度。后续升级用innodb_autoinc_lock_mode,如果存在批量插入情况,一次性插入的值可以确定,就可以直接一次性申请多个id,合并申请释放一次。

6.行锁、间隙锁、next-key lock

间隙锁是为了解决幻读的问题。

next锁形式是多个区间,左开右闭。

法则:

等值查询,唯一索引,next锁降级为行锁,唯一索引必须保证唯一,每次插入要检查,不一样一定能插入新行,没必要锁住行。

等值查询,最后扫描的一个行不满足条件的时间,最后一个退化为间隙锁(右开)。

访问到的对象才会加锁。走索引和全表扫描是两情况,覆盖索引不访问主键索引树,主键索引依然可以操作。

7.MDL

MDL是自动加上的,不需要显式使用,增删改查DML是读锁,表结构变更DDL是写锁。

经典死锁问题:线程A申请了DML,线程B申请DDL被阻塞,会阻塞后面所有的DML,如果查询频繁或者有重试机制,线程会爆满。

可以为DDL操作设置心跳机制。