一次死锁的排查过程

举报
yd_252271337 发表于 2026/11/09 11:49:50 2026/11/09
【摘要】 # 一次死锁的排查过程数据库报 Deadlock found,业务偶发失败。死锁不难解决,难的是定位是哪两个事务在互相等。这篇记一次实际排查。## 现象订单创建偶发失败,日志里有 `Deadlock found when trying to get lock`。不是必现,高峰期更容易出现。## 第一步:看死锁日志MySQL 兼容库有 `SHOW ENGINE INNODB STATUS`,里...

# 一次死锁的排查过程

数据库报 Deadlock found,业务偶发失败。死锁不难解决,难的是定位是哪两个事务在互相等。这篇记一次实际排查。

## 现象

订单创建偶发失败,日志里有 `Deadlock found when trying to get lock`。不是必现,高峰期更容易出现。

## 第一步:看死锁日志

MySQL 兼容库有 `SHOW ENGINE INNODB STATUS`,里面有一段 LATEST DETECTED DEADLOCK,记录最近一次死锁的两个事务和它们持有的锁。

```sql
SHOW ENGINE INNODB STATUS\G
```

重点看:

- 两个事务分别执行了什么 SQL
- 各自持有什么锁、在等什么锁

## 第二步:还原场景

那次日志显示:

- 事务 A:先更新订单表,再更新库存表
- 事务 B:先更新库存表,再更新订单表

两个事务加锁顺序相反,交叉等待,形成死锁。

## 第三步:解决

**统一加锁顺序**:所有涉及这两张表的事务,都按「订单 → 库存」的顺序加锁。顺序一致就不会交叉。

**缩小事务范围**:事务里别做耗时操作,尽快提交,减少持锁时间。

**降低隔离级别**:如果业务允许,用 READ COMMITTED 减少间隙锁。

**加索引减少锁范围**:没有索引的更新会锁更多行,容易冲突。

## 预防措施

- 约定资源加锁顺序,写进开发规范
- 事务尽量短
- 更新条件走索引
- 高频冲突的表考虑拆分

## 死锁不是 bug

要理解:死锁是数据库的一种自我保护,检测到就回滚一个事务。应用层遇到死锁应该重试,而不是当成致命错误。

```python
for attempt in range(3):
    try:
        do_transaction()
        break
    except DeadlockError:
        time.sleep(0.1 * (attempt + 1))
```

## 小结

死锁排查靠死锁日志,解决靠统一加锁顺序和缩短事务。应用层要有重试机制。死锁本身不可怕,可怕的是不知道为什么会死锁。把加锁顺序规范起来,能消除大部分死锁。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。