提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 插入意向锁
- MySQL执行插入Insert时的加锁过程
- MySQL官方文档
- MySQL insert加锁流程
- 1.加插入意向锁
- 2.判断插入记录是否有唯一键
- 3. 插入记录并对记录加X锁
- ==插入意向锁----> S锁----> X锁---->执行插入==
- 案例
- 在这里插入图片描述 insert加锁的小结
- 建议:
插入意向锁
MySQL执行插入Insert时的加锁过程
MySQL官方文档
MySQL官方文档对Insert加锁情况的描述
解读:
-
INSERT操作会对新插入的记录加行锁写锁(排它锁X锁);注意:区别于执行update,执行insert时这里加的是X锁,并非next-key lock,因此不会阻塞其他的事务对gap区间的插入操作;
-
在插入记录前,会向插入记录所在位置申请意向插入意向锁(Insertion Intention Gap Lock);只要不是插入的是同一行记录,多个事务对相同gap区间的插入意向锁操作不会冲突;
-
对于唯一索引,发生唯一键冲突时,当前事务会先尝试在这条记录上加读锁S锁;加S锁的机制可能会导致死锁:即A线程占用记录的X锁,B、C阻塞,它们需要先获取S锁再获取X锁执行更新;当A释放X锁时,B、C同时拿到S锁(共享锁),但互相都无法继续获取X锁(S锁与X锁互斥),导致死锁;
MySQL insert加锁流程
1.加插入意向锁
- 首先对插入的间隙加插入意向锁(Insert Intension Locks);注意插入意向锁可以理解为只是个插入动作,并非真的加锁
- 如果该间隙已被加上了GAP锁(间隙锁)或 Next-Key 锁(含GAP 锁),则加锁失败,等待间隙释放;
- 如果没有,则加插入意向锁成功,表示可以插入;只要不是插入的是同一行记录,多个事务对相同gap区间加插入意向锁不会冲突;
2.判断插入记录是否有唯一键
[可选 唯一键]然后判断插入记录是否有唯一键,如果有,则需要进行唯一性约束检查:
- 如果不存在相同键值,则准备插入;
- 如果存在相同键值,则判断该键值是否加锁;
如果没有锁, 判断该记录是否被标记为删除;
- 如果标记为删除,说明删除事务已经提交,数据页上的记录还没来得及 purge,这时尝试加S锁;
- 如果没有标记删除,说明数据已存在,本次插入会导致唯一键冲突,则报 1062 duplicate key 错误;
如果有锁,说明该记录正在被处理(正在被其他事务新增、删除或更新),且其他事务还未提交,则当前事务尝试加S锁后会进入阻塞,等待其他事务释放记录X锁;
3. 插入记录并对记录加X锁
插入记录并对记录加X锁,当前事务提交或回滚时释放X锁;
插入意向锁----> S锁----> X锁---->执行插入
案例
insert加锁的小结
- 关于隐式锁,一般使用自增主键且不含唯一键的insert语句,并发时不会有冲突,因为插入意向锁是隐式锁,实际代表的是一个准备插入的行为;这个行为只和间隙锁GAP锁冲突;
- 关于锁升级,当插入的数据含唯一键,出现并发插入时(如事务A和事务B,事务A先执行insert但还未提交事务),后执行插入的事务B会使用当前读,如果发现这条记录已存在(还未提交),则会先尝试获取S锁;此时事务A的插入意向锁(隐式锁)会被提升为显式锁( X 锁),导致事务B阻塞;
- 关于插入死锁;正是MySQL这种唯一键冲突时的insert插入获取锁的规则,导致了在[case2:并发插入事务中的顺序顺序不一致]、[case3: 删除提交但还未purge]、或[case4: 并发插入事务中单条回滚]的case下,会出现并行的事务先拿到S锁(共享锁),但在执行insert加X锁时,发现阻塞,构成死锁;这个问题在MySQL官方文档也提到了;
建议:
- 针对case2,保证各个事务线程执行插入时,插入数据的顺序相同,避免死锁;尽量保证数据有序插入
- 针对case3和case4,保证各个事务线程执行含唯一键的数据插入前,先对数据加X锁,即跳过insert加锁机制的先尝试获取S锁这一阶段;如select … for update;如果查到了,则跳过插入;