项目中某个定时任务执行过程中出现死锁问题,具体错误如下:
1 | Error 1213: Deadlock found when trying to get lock; try restarting transaction |
分析
检查一下表引擎 & 事务隔离级别
1 | mysql> show variables like '%storage_engine%'; |
默认使用的引擎是InnoDB,Insert、Update、Delete操作会触发排它锁(X锁)即行锁,所以怀疑是不是触发了共享锁(S锁)。
1 | mysql> show engine innodb status; |
通过以上信息确认是因为[事务1]Insert & [事务2]Delete互相等待对方事务释放锁的问题造成死锁,最后[事务1]进行回滚。
原因
review代码梳理一下业务逻辑,场景应该如下:
| trx1 | trx2 |
| —— | —— | —— |
| | BEGIN |
| BEGIN | DELETE FROM user_tag_distributes
WHERE app_id = ‘im’ and tag_name = ‘churn_model_v2’ |
| DELETE FROM user_tag_distributes
WHERE app_id = ‘im’ and tag_name = ‘churn_model_v2’ | |
| INSERT INTO user_tag_distributes
(created_at
,updated_at
,deleted_at
,app_id
,tag_name
,tag_value
,account_num
) VALUES (‘2021-11-12 14:21:02.386’,’2021-11-12 14:21:02.386’,NULL,’im’,’churn_model_v2’,’0.70709264’,1) | |
| ERROR 1213 (40001): Deadlock found when trying to get lock | |
| ROLLBACK | … |
| | COMMIT |
可以看出[事务1]进行Insert操作时发现[事务2]进行Delete操作且已申请X锁,[事务1]想要获取S锁则需要[事务2]提交,所以[事务1]、[事务2]在相互等待对方提交事务(释放锁)。
解决方案
目前想到的几种措施:
- 尽量避免在并发程序中Delete & Insert操作无缝执行
- 并发程序采用分布式锁控制
- 程序不允许并发执行
https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html
https://dev.mysql.com/doc/refman/8.0/en/innodb-standard-monitor.html