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

如何让DB::transaction在重试前等待以避免死锁?

给Laravel事务重试添加间隔时间解决死锁问题

Laravel原生的DB::transaction()方法在处理重试时确实没有内置延迟机制,所有重试会立即执行,对死锁场景帮助有限。要快速实现带延迟的重试,你可以自己封装一个事务处理函数,手动控制重试间隔:

封装带延迟重试的事务函数

function transactionWithDelay(callable $callback, int $attempts = 3, int $delayMs = 1000)
{
    $attemptCount = 0;

    retryLoop:
    try {
        // 让原生事务只执行1次,我们自己控制重试逻辑
        return DB::transaction($callback, 1);
    } catch (\Illuminate\Database\QueryException $e) {
        // 匹配死锁对应的错误码,根据你的数据库调整:
        // MySQL: 1213, PostgreSQL: 40P01, SQL Server: 1205
        $deadlockErrorCodes = [1213, 40P01];
        
        if (in_array($e->getCode(), $deadlockErrorCodes) && ++$attemptCount < $attempts) {
            // 转换为微秒等待,比如1000ms = 1秒
            usleep($delayMs * 1000);
            goto retryLoop;
        }

        // 非死锁异常或重试次数耗尽,抛出原异常
        throw $e;
    }
}

使用示例

把你的事务逻辑传入这个函数即可,指定重试次数和间隔时长:

// 重试3次,每次间隔2秒
transactionWithDelay(function () {
    // 这里放你的导入流程事务逻辑
    $this->handleImportStep();
}, 3, 2000);

注意事项

  • 错误码适配:不同数据库的死锁错误码不同,一定要根据你使用的数据库调整$deadlockErrorCodes数组里的值
  • 延迟时长:建议设置1-5秒的间隔,具体根据你的业务执行时长调整,确保其他冲突事务有足够时间释放锁
  • 临时方案提醒:这个方法只是临时规避死锁的手段,长期来看还是要优化你的迭代逻辑,缩短事务时长、减少锁的范围,从根源解决死锁问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:08:23