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

如何在CodeIgniter 3.x中处理MySQL死锁错误?常规try-catch无效

CodeIgniter 3.x 处理MySQL死锁错误的可行方案

常规try-catch失效的核心原因是:CodeIgniter 3.x的数据库类默认不会抛出异常,而是将错误信息存储在$this->db->error()中,直接用try-catch无法捕获死锁错误。以下是具体解决办法:

1. 临时开启错误检查+死锁重试

先关闭数据库自动调试,手动检查错误码(MySQL死锁错误码为1213),遇到死锁时重试操作:

// 启动事务
$this->db->trans_start();
// 临时关闭自动调试,避免CI直接输出错误
$this->db->db_debug = FALSE;

$retryCount = 3;
$success = FALSE;

while ($retryCount > 0 && !$success) {
    // 执行你的数据库操作(示例:更新数据)
    $this->db->update('your_table', $updateData, $whereCondition);
    
    $dbError = $this->db->error();
    if (empty($dbError['code'])) {
        // 操作成功
        $success = TRUE;
    } elseif ($dbError['code'] != 1213) {
        // 非死锁错误,直接抛出异常
        throw new Exception($dbError['message'], $dbError['code']);
    }
    
    $retryCount--;
    if (!$success) {
        // 等待随机时长(100-500ms),避免重复冲突
        usleep(rand(100000, 500000));
    }
}

if ($success) {
    $this->db->trans_complete();
} else {
    $this->db->trans_rollback();
    throw new Exception('多次重试后仍未解决死锁');
}

// 恢复默认调试设置(根据你的配置调整)
$this->db->db_debug = TRUE;

2. 封装通用重试函数

把死锁重试逻辑封装成可复用函数,减少重复代码:

/**
 * 带死锁重试的数据库事务执行函数
 * @param callable $callback 要执行的数据库操作闭包
 * @param int $retryTimes 最大重试次数
 * @throws Exception
 */
function run_with_deadlock_retry($callback, $retryTimes = 3) {
    $this->db->trans_start();
    $this->db->db_debug = FALSE;
    
    $success = FALSE;
    $attempts = 0;
    
    while ($attempts < $retryTimes && !$success) {
        try {
            // 执行传入的数据库操作
            call_user_func($callback);
            
            $dbError = $this->db->error();
            if (empty($dbError['code'])) {
                $success = TRUE;
            } elseif ($dbError['code'] != 1213) {
                throw new Exception($dbError['message'], $dbError['code']);
            }
        } catch (Exception $e) {
            $this->db->trans_rollback();
            throw $e;
        }
        
        $attempts++;
        if (!$success) {
            usleep(rand(100000, 500000));
        }
    }
    
    if ($success) {
        $this->db->trans_complete();
    } else {
        $this->db->trans_rollback();
        throw new Exception('死锁重试失败,已回滚事务');
    }
    
    $this->db->db_debug = TRUE;
}

// 使用示例
$this->run_with_deadlock_retry(function() {
    $this->db->update('order', ['status' => 'paid'], ['id' => $orderId]);
    $this->db->insert('payment_log', ['order_id' => $orderId, 'amount' => $amount]);
});

3. 从根源减少死锁发生

除了重试,优化业务逻辑和数据库操作能降低死锁概率:

  • 缩短事务执行时间:不要在事务中执行非数据库操作(如API调用、复杂计算)
  • 统一表访问顺序:所有事务都按相同顺序操作表(比如先操作订单表,再操作商品表),避免交叉锁
  • 使用行级锁:尽量用带主键/唯一索引的WHERE条件(如UPDATE ... WHERE id = ?),减少锁范围
  • 避免长时间持有锁:事务中不要等待用户输入或外部响应

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:17:39