死锁日志的查看
https://segmentfault.com/a/1190000018730103
sql
1 | show engine innodb status; |
记录锁,间隙锁,Next-key 锁和插入意向锁。这四种锁对应的死锁如下:
记录锁(LOCK_REC_NOT_GAP): lock_mode X locks rec but not gap
间隙锁(LOCK_GAP): lock_mode X locks gap before rec
Next-key 锁(LOCK_ORNIDARY): lock_mode X
插入意向锁(LOCK_INSERT_INTENTION): lock_mode X locks gap before rec insert intention
死锁案例
https://my.oschina.net/hebaodan/blog/1835966
https://my.oschina.net/hebaodan/blog/3033276
gap锁 + 并发insert死锁
表及Sql
分析
锁冲突矩阵
并发delete + insert唯一键冲突死锁
表及场景sql:
分析
死锁日志
1 | *** (1) TRANSACTION: |
sql加锁分析
https://www.aneasystone.com/archives/2017/12/solving-dead-locks-three.html (这是一个系列)
基本加锁规则
- 常见语句的加锁
- select 快照读,在RC和RR下不加锁
- select … lock in share mode为当前读,加S锁
- select … for update为当前读,加X锁
- dml语句,当前读,加X锁
- ddl语句,加标记所,隐式提交,不能回滚。
- 表锁
- 表锁(S和X锁)
- 意向锁(IS锁和IX锁)
- 自增锁(一般看不见 只有在innodb_autoinc_lock_mode=0或者bulk inserts时才可能有)
- 行锁
- 记录锁(S和X锁)
- 间隙锁(S和X锁)
- Next-Key锁(S和X锁)
- 插入意向锁
- 行锁分析
- 行锁是加在索引上的,最终都会落在聚簇索引上。
- 加行锁是一行行加的
锁冲突
不同隔离级别下的锁
- select快照读在Serializable隔离级别下为当前读,加S锁。
- RC下没有间隙锁和Next-Key锁(唯一索引情况下有特殊,purge线程+记录有锁唯一索引,会加S Next-Key锁)
对于insert操作
如果没有这两个问题
(1)为了防止幻读,如果记录之间加有 GAP 锁,此时不能 INSERT;(插入意向锁解决)
(2)如果 INSERT 的记录和已有记录造成唯一键冲突,此时不能 INSERT;(对已存在唯一记录加S Next锁)
- insert一开始只有隐式锁,除非隐式锁转换为显式锁: InnoDb 在插入记录时,是不加锁的。如果事务 A 插入记录且未提交。
如果这时事务 B 尝试对这条记录加锁,事务 B 会先去判断记录上保存的事务 id 是否活跃,如果活跃的话,那么就帮助事务 A 去建立一个锁对象,然后自身进入等待事务 A 状态,这就是所谓的隐式锁转换为显式锁。还比如对于辅助索引也是隐式锁。
- insert 对唯一索引的加锁逻辑:
- 1.先做UK冲突检测,如果存在目标行,先对目标行加S Next Key Lock(该记录在等待期间被其他事务删除,此锁被同时删除)
- 2.如果1成功,对对应行加插入意向锁
- 3.如果2成功,插入记录,并对记录加X + 行锁(有可能是隐式锁)