JJava 知识库
JAVA INTERVIEW

高频面试题

MySQL高级约 3 分钟

支付回调和退款任务并发更新订单时频繁死锁,你会怎么查死锁日志并改造代码?

参考回答约 3 分钟 · 口语表达
先说结论

我会先控制影响,再按证据定位:掌握记录锁、间隙锁、Next-Key Lock、意向锁以及死锁诊断

01

我会先确认影响范围,同时控制故障继续放大。能否区分共享锁、排他锁、记录锁、间隙锁和 Next-Key Lock。 是否理解 InnoDB 所谓“行锁”实际加在索引记录上。 能否结合隔离级别、索引与查询条件分析锁范围。 是否知道死锁不是简单的“两个事务同时更新”。 是否具备从等待关系、SQL、事务和索引定位线上问题的能力。

02

止损之后,我会按请求链路建立证据,而不是凭经验猜。沿着「事务定位索引记录 → 申请记录或间隙锁 → 冲突后进入等待 → 等待图形成环或超时 → 选择牺牲者回滚」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 事务定位索引记录 InnoDB 锁作用于索引记录;没有合适索引时扫描和锁定范围可能远超业务认知。 申请记录或间隙锁 Record、Gap 与 Next-Key Lock 组合用于记录互斥和防止特定范围幻读,隔离级别与语句类型会改变行为。 performanceschema.datalocks:当前锁对象与模式。 SHOW ENGINE INNODB STATUS:LATEST DETECTED DEADLOCK 图。 我会先确认请求实际走到了哪条路径,再用运行数据验证,不会只看类名或配置猜测。

03

定位时我最关注这些参数、指标和容量关系。两个事务反序更新相同 ID,复现死锁;加排序与索引后循环并发 10 万次比较死锁率。

04

找到根因后先做最小修复,再用同样的流量验证。两个订单任务分别按输入顺序更新商品库存,相同商品集合顺序不同,形成交叉锁。提交前按 skuid 排序并缩短事务后,死锁显著下降;重试仍保留以处理其他不可避免冲突。 缺少索引导致锁范围扩大:锁等待时间:按主键排序更新。 事务内调用远程服务长期持锁:死锁日志频率:远程调用移出事务。 捕获死锁后只重试单条语句:事务持续时间:完整事务有界退避重试。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「事务 P99」为主基线,记录值应满足「低于接口预算」;同时保存 锁等待时间、死锁日志频率,使后续变化能够回到同一时间轴比较。

05

恢复阶段要逐步放量,最后把监控和边界补齐。方案:更适合的场景:主要收益:代价与边界。 一致加锁顺序:同类批量资源:从设计上减少环:所有路径必须遵守。 短事务 + 有界重试:冲突偶发且操作幂等:恢复简单、吞吐较好:重试会增加瞬时负载。 串行化/分区队列:热点键冲突极高:消除同键并发竞争:增加排队与分区治理。 选型至少带上 数据规模、选择性、读写比、事务长度和峰值并发,并用上面的量化基线验证;未知数据应明确为待测假设。

排查与恢复时间线从目标到落地
01事务定位索引记录
02申请记录或间隙锁
03冲突后进入等待
04等待图形成环或超时
05选择牺牲者回滚