来源: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; 死锁出现

预防死锁

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

总结

MySQL锁这块知识真的很多,需要我们平时不断思考和积累。本次主要介绍当线上遇到死锁的情况,我们怎样去定位,排查和分析。通过SHOW ENGINE INNODB STATUSG查看最后一次死锁情况,找出导致死锁的SQL语句,再分析具体的死锁原因,比如持有什么锁,等待什么锁。最后验证修复死锁问题。

本篇文章来源于微信公众号: 业余草



微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2024-08-01