线上死锁问题定位

本文详细介绍了线上业务中遇到的死锁问题,涉及两个大任务并发执行时对同一关联关系表进行更新导致的死锁。通过对死锁语句的分析,发现锁粒度过粗及事务过大是问题根源。解决方案包括创建更精确的索引以细化锁粒度,并将大事务拆分成多个小事务立即提交,以减少锁竞争。同时,提供了检查数据库状态、锁等待时间和分析SQL命中索引的方法,以及Spring事务管理的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线上死锁问题定位

什么是死锁

问题

业务上有个异步任务,这个任务包含许多http接口,多个接口是串行,此任务中的接口数是根据操作人员的选择动态生成的;每个接口同步返回后又会更新关联表。


这个时候会出现两个大任务A和B,每个任务又包含了几十个接口,碰巧这两个任务的子接口里又有维护相同关联关系表的数据,就会报:DeadlockLoserDataAccessException

问题解析

首先检测到了导致死锁的语句

-- 第一条
update by_oedu_lesson_relation SET is_deleted = 1, last_update_id = 11419, last_update_time = '2022-08-31 15:03:00.659' 
WHERE ( is_deleted = 0 and tenant_id = 1 and class_id = 117 and schedule_id = 1437 and student_id = 2108171 );

-- 第二条
update by_oedu_lesson_relation SET is_deleted = 1, last_update_id = 11419, last_update_time = '2022-08-31 15:03:00.687'
WHERE ( is_deleted = 0 and tenant_id = 1 and class_id = 117 and schedule_id = 1465 and student_id = 2108171 );

通过explain分析此语句命中了 class_id 的索引,innodb引擎默认的锁是行锁,所以可以看到两条语句明明不是同一条记录为何会有锁的竞争,因为锁的是以class_id为维度的多行记录。

注:如果没有命中索引,锁的是整张表

最后通过阿里云的"一件诊断"中的"锁分析"得出了相同的分析结果:
死锁

解决方案

通过分析问题,得出了两个需要优化的地方

  1. 锁粒度太粗,不应该只命中 class_id,需要增加 schedule_id & student_id 联合索引
  2. 事务太大,一个任务如果包含了几十个http接口怎么说也要几十秒才能提交事务;得出的结论是把每个接口和其对应的数据维护包成一个子任务,新建一个事务,处理后直接提交(前提是整个任务错误时不需要回滚)

涉及到的相关手段

  • sql
-- innodb 状态信息
SHOW ENGINE INNODB STATUS;

-- 锁等待时间
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';

-- 通过explain查看命中索引
explain update by_oedu_lesson_relation SET is_deleted = 1, last_update_id = 11419, last_update_time = '2022-08-31 15:03:00.687'
WHERE ( is_deleted = 0 and tenant_id = 1 and class_id = 117 and schedule_id = 1465 and student_id = 2108171 );
  • Spring事务
// 新启事务
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
<!-- 获取当前事务 为了验证开启事务是否生效-->
<select id="getTransactionId" resultType="java.lang.String" >
        SELECT TRX_ID
        FROM INFORMATION_SCHEMA.INNODB_TRX
        WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();
</select>
 WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();
</select>
课程简介: 课程总计41课时,从什么是事务讲起,直到分布式事务解决方案,很的0基础基础与提升系列课程。对于难以理解的知识点,全部用画图+实战的方式讲解。 第一部分:彻底明白事务的四个特性:原子性、一致性、隔离性、持久性,用场景和事例来讲解。 第二部分:实战讲数据库事务的6中并发异常:回滚丢失、覆盖丢失、脏读、幻读、不可重复读、MVCC精讲。 第三部分:彻底搞清楚4种事务隔离级别:READ_UNCOMMITTED 读未提交隔离级别、READ_COMMITTED 读已提交隔离级别、REPEATABLE_READ 可重复度隔离级别、SERIALIZABLE 序列化隔离级别 第四部分:彻底搞清楚MySQL的各种锁:行锁、表锁、共享锁、排它锁、Next-Key锁、间隙锁、X锁、S锁、IS锁、IX锁、死锁、索引与锁、意向锁等。 第五部分:彻底搞清楚Spring事务的7种传播级别的原理和使用:PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY、PROPAGATION_REQUIRES_NEW、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER、PROPAGATION_NESTED分布式事务的理论基础:RPC定理、BASE理论、XA协议都是什么,原理是什么,有什么关联关系 第六部分:分布式事务的5种解决方案原理和优缺点:2PC两阶段提交法、3PC三阶段提交法、TCC事务补偿、异步确保策略、最大努力通知策略 第七部分:阿里巴巴分布式事务框架Seata:历经多年双十一,微服务分布式事务框架,用一个Nacos+Spring Cloud+Seta+MySql的微服务项目,实战讲解阿里的分布式事务技术,深入理解和学习Seata的AT模式、TCC模式、SAGA模式。 课程资料: 课程附带配套2个项目源码72页高清PDF课件一份阿里巴巴seata-1.1.0源码一份阿里巴巴seata-server安装包一份
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值