来源:juejin.cn/post/7038156758614802440
推荐:https://t.zsxq.com/SyOqf
前言
最近在并发量稍微高的情况,线上出现很多deadlock日志,日志中同时也打印出表名和MDL,是一条insert语句。于是,我查看表结构和代码中真正的执行语句。(这里为了避免使用真实表,我稍微改了一下表名和字段名。)
隔离级别:RR
数据库版本:5.7
表结构
CREATETABLEIFNOTEXISTS`t_test`(idBIGINTUNSIGNEDNOTNULLAUTO_INCREMENT,useridBIGINT(11)NOTNULL,seqBIGINT(20)UNSIGNEDNOTNULL,PRIMARYKEY(id),UNIQUEKEY_uk_userid(userid),KEY_k_userid_seq(userid,seq))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;
表初始化数据

| 时间 | 事务1 | 事务2 | 事务3 |
|---|---|---|---|
| T1 | begin;insert into t_test (userid,seq) values (6,1638504289244987791) on duplicate key update seq=seq+1;获取插入意向锁,排它的间隙锁(5,10);执行插入成功; | ||
| T2 | begin;insert into t_test (userid,seq) values (7,1638504289244987791) on duplicate key update seq=seq+1;准备插入意向锁,等待事务1的间隙锁; | ||
| T3 | 锁等待中 | insert into t_test (userid,seq) values (8,1638504289244987791) on duplicate key update seq=seq+1;准备插入意向锁,等待事务1的间隙锁; | |
| T4 | 锁等待中 | ||
| T5 | rollback; | 死锁出现 |

预防死锁
-
尽量使用 INSERT来替换INSERT...ON DUPLICATE KEY UPDAT。INSERT将在唯一键和主键中添加记录 x 锁,而不是获取间隙锁,因此不会造成死锁。 -
使用 INSERT,然后业务上判断duplicate-key错误,进行UPDATE操作。 -
尽量减少使用唯一键,可以的话从业务层面保证。

总结
MySQL锁这块知识真的很多,需要我们平时不断思考和积累。本次主要介绍当线上遇到死锁的情况,我们怎样去定位,排查和分析。通过SHOW ENGINE INNODB STATUSG查看最后一次死锁情况,找出导致死锁的SQL语句,再分析具体的死锁原因,比如持有什么锁,等待什么锁。最后验证修复死锁问题。
本篇文章来源于微信公众号: 业余草
微信扫描下方的二维码阅读本文

Comments NOTHING