在测试同学测试过程中偶然发现日志中出现异常死锁日志如下:
出现问题后,立刻定位日志,排查死锁原因。以下为排查过程,图片不是很清晰,也不知道是为什么?
测试环境日志1. 登录测试服务器使用命令show engine innodb status,查看innodb锁状态等相关信息。
2.定位到死锁日志,查看死锁相关事务的锁状态以及锁相关的信息,持有状态等。
事务1
innodb锁状态事务1事务2
innodb锁状态事务2分析发现,通过lock_mode X waiting 可以判断出来,事务1 在等待X 排他锁(此锁是加在唯一索引上)事务2 持有X锁(唯一索引上的X锁),但是由于此insert 使用了ON DUPLICATE KEY UPDATE UPDATE_COUNT = (UPDATE_COUNT+1) ,原理是,唯一索引冲突时只更新次数 不插入数据, 所以导致在事务2持有X锁后,还需要获取插入意向锁,专业术语,先做UK冲突检测,也就是日志中事务2上面的 lock_mode X locks gap before rec insert intention waiting, 因为对同一个字段的锁的申请是需要排队的,因为在事务1里已经在申请X排队,所以事务2申请S意向锁要X锁后排这,这就导致了事务1和事务2循环等待,导致死锁。
此问题的根本原因是,批量插入时,由于业务需要使用ON DUPLICATE KEY UPDATE来处理当唯一索引或者主键冲突时,只更新业务记录的次数,导致A-insert语句在和B-insert语句并发时,A和B操作的唯一索引相同(出现相同insert是因为过滤数据时未做排重处理),引起以上锁竞争场景,同学们引以为戒。
网友评论