You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何区分PDOException中的语法错误、死锁及连接错误以优化处理?

区分PDOException错误类型并实现重试逻辑

要实现PDO异常的类型区分和针对性重试,核心是利用PDOException的两个关键属性:$exception->getCode()(SQLSTATE标准错误码)和$exception->errorInfo[1](数据库原生错误码,比如MySQL的具体错误编号)。以下是具体实现方案:

1. 明确不同错误对应的标识码

以MySQL为例,常见需区分的错误码如下:

  • 死锁(Deadlock):原生错误码1213,SQLSTATE码40001
  • 连接类错误:连接超时2002、连接丢失2013、连接数超限1040,SQLSTATE多为HY000
  • 语法错误:原生错误码1064,SQLSTATE码42000
  • 参数/数据错误:字段值过长1406,SQLSTATE码22001

2. 代码实现示例

先封装错误类型判断函数,再在事务逻辑中加入重试机制:

// 判断是否为可重试的错误类型
function isRetriablePDOError(PDOException $e) {
    // 可重试的MySQL原生错误码
    $retryNativeCodes = [
        1213, // 死锁
        2002, // 连接超时
        2013, // 查询过程中连接丢失
        1040, // 数据库连接数过多
    ];
    // 可重试的SQLSTATE码
    $retrySqlStates = [
        '40001', // 死锁标准码
    ];

    // 优先用原生错误码判断(更精准)
    if (in_array($e->errorInfo[1], $retryNativeCodes)) {
        return true;
    }
    // 补充SQLSTATE码判断
    if (in_array($e->getCode(), $retrySqlStates)) {
        return true;
    }
    // 针对HY000这类通用连接错误,需排除非重试场景
    if ($e->getCode() === 'HY000') {
        $nonRetryHy000Codes = [1064, 1406];
        return !in_array($e->errorInfo[1], $nonRetryHy000Codes);
    }
    return false;
}

// 业务事务处理+重试逻辑
$maxRetries = 3;
$retryCount = 0;
$operationSuccess = false;

do {
    try {
        $pdo->beginTransaction();
        
        // 执行你的业务SQL:插入/更新/删除
        $stmt = $pdo->prepare("INSERT INTO target_table (col1, col2) VALUES (:val1, :val2)");
        $stmt->execute([':val1' => $val1, ':val2' => $val2]);
        
        $pdo->commit();
        $operationSuccess = true;
    } catch (PDOException $e) {
        // 回滚事务
        $pdo->rollBack();
        // 记录错误详情
        error_log(
            sprintf(
                "PDO Error: %s | Native Code: %s | SQLSTATE: %s",
                $e->getMessage(),
                $e->errorInfo[1],
                $e->getCode()
            )
        );
        
        if (isRetriablePDOError($e) && $retryCount < $maxRetries) {
            $retryCount++;
            // 重试前加入短暂延迟,降低再次死锁概率
            usleep(500000); // 500毫秒
        } else {
            // 非重试类错误(语法/参数错误),直接跳过
            error_log("Non-retriable error, skipping current operation.");
            break;
        }
    }
} while (!$operationSuccess && $retryCount <= $maxRetries);

3. 关键注意事项

  • 不同数据库的错误码存在差异,比如PostgreSQL死锁的SQLSTATE是40P01,需根据实际使用的数据库调整错误码列表
  • 不要盲目重试HY000类型错误,该SQLSTATE包含大量非重试场景,必须结合原生错误码过滤
  • 限制重试次数,避免无限循环占用资源
  • 语法错误、参数越界属于代码逻辑问题,重试无意义,直接跳过即可

内容的提问来源于stack exchange,提问作者inf3rno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:42:10