← 返回错误码列表

MySQL错误码 1213 分析与解决方案

错误信息

Error 1213

死锁发现;尝试重启事务。

你的PHP应用在使用PDO连接MySQL时遇到了死锁问题:

'pdo_code' => '40001',
'db_code' => 1213,
'db_error' => 'Deadlock found when trying to get lock; try restarting transaction'

解决方案

  • 实现事务重试机制(最有效的方法)
  • 减少事务执行时间,尽快提交事务
  • 按固定顺序访问多个表中的数据
  • 为高频查询字段添加合适的索引
  • 在允许的情况下降低事务隔离级别
  • 将大事务拆分为多个小事务

PHP重试机制示例代码

// 最大重试次数
$maxRetries = 3;
$retryCount = 0;

while ($retryCount < $maxRetries) {
  try {
    // 开始事务
    $pdo->beginTransaction();

    // 执行数据库操作...
    // UPDATE table1 SET ...
    // UPDATE table2 SET ...

    // 提交事务
    $pdo->commit();
    break; // 成功则退出循环
  } catch (PDOException $e) {
    // 检查是否为死锁错误
    if ($e->getCode() == '40001' || $e->getCode() == '1213') {
      $retryCount++;
      // 回滚当前事务
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      // 等待随机时间后重试(避免多个进程同时重试)
      usleep(rand(100000, 500000));
    } else {
      // 非死锁错误,重新抛出异常
      throw $e;
    }
  }
}

if ($retryCount == $maxRetries) {
  // 记录错误或抛出异常
  throw new Exception("事务在重试{$maxRetries}次后仍然失败");
}

死锁模拟演示

死锁通常发生在两个或多个事务相互等待对方释放锁时:

事务 A

1. 更新 用户表 (获取锁)

2. 尝试更新 订单表 (等待事务B释放锁)...

事务 B

1. 更新 订单表 (获取锁)

2. 尝试更新 用户表 (等待事务A释放锁)...

MySQL检测到死锁

选择回滚其中一个事务(通常是修改数据量较少的事务)

被回滚的事务将收到错误:1213

预防措施

1. 应用层优化

  • 保持事务简短
  • 按固定顺序访问表
  • 使用重试机制

2. 数据库层优化

  • 添加合适的索引
  • 优化查询语句
  • 考虑使用READ COMMITTED隔离级别
  • 必要时使用表锁(谨慎使用)

3. 架构层优化

  • 将热点数据拆分到不同表
  • 使用队列处理高并发写操作
  • 考虑使用悲观锁或乐观锁

调试工具

使用以下MySQL命令分析死锁:

# 查看最近的死锁信息
SHOW ENGINE INNODB STATUS;

死锁分析要点

LATEST DETECTED DEADLOCK 部分包含:

  • 涉及的事务
  • 每个事务正在执行的SQL语句
  • 事务等待的锁
  • 被回滚的事务