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

如何封装带Try-Catch与重试逻辑的可复用For循环?

解决方案:封装可复用的数据库重试逻辑

Hey there! You want to wrap that retry-on-QueryException logic into a reusable function so you only need to pass in your actual business code—smart move. Here's a clean way to implement this:

1. 创建可复用的重试函数

你可以把这个函数定义为全局辅助函数(添加到项目的helpers.php文件中),或者放在服务类里,根据你的代码结构选择即可:

function loop(callable $callback, int $maxAttempts = 2)
{
    for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
        try {
            // 执行传入的业务逻辑,同时保留返回值
            return $callback();
        } catch (\Illuminate\Database\QueryException $e) {
            // 如果是最后一次尝试,不再重试,直接抛出异常
            if ($attempt === $maxAttempts - 1) {
                throw $e;
            }
            // 否则继续循环重试
        }
    }
}

代码说明:

  • callable $callback: 接收一个闭包参数,你需要执行的业务逻辑(比如创建用户、更新数据)都写在这里面
  • int $maxAttempts = 2: 默认设置为2次尝试(1次初始执行 + 1次重试),调用时可以根据需求自定义次数
  • 使用return $callback()确保业务逻辑的返回值能传递回调用处
  • 仅捕获QueryException,其他异常会直接抛出,和你原来的代码行为保持一致

2. 按你想要的方式调用

现在你可以完全摆脱重复的循环和捕获代码,只需要传入业务逻辑即可:

// 示例1:创建用户
loop(function() {
    return User::create([
        'name' => 'user name'
    ]);
});

// 示例2:更新数据
loop(function() {
    return User::where('id', 42)->update([
        'email' => 'updated@example.com'
    ]);
});

// 示例3:自定义尝试次数(比如总共3次尝试)
loop(function() {
    return Order::create(['total' => 99.99]);
}, 3);

3. 可选进阶优化:让函数更灵活

如果需要适配更多场景,可以扩展函数支持自定义捕获异常类型和重试延迟:

function retryOnException(callable $callback, int $maxAttempts = 2, array $allowedExceptions = [\Illuminate\Database\QueryException::class], int $retryDelayMs = 0)
{
    for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
        try {
            return $callback();
        } catch (\Throwable $e) {
            // 检查当前异常是否在允许重试的列表中
            $shouldRetry = collect($allowedExceptions)->contains(fn($exceptionClass) => $e instanceof $exceptionClass);
            
            // 如果不允许重试,或者是最后一次尝试,直接抛出异常
            if (!$shouldRetry || $attempt === $maxAttempts - 1) {
                throw $e;
            }
            
            // 如果设置了延迟,等待后再重试
            if ($retryDelayMs > 0) {
                usleep($retryDelayMs * 1000); // 毫秒转微秒
            }
        }
    }
}

调用进阶版的示例:

// 允许在QueryException和PDOException时重试,共3次尝试,每次间隔500毫秒
retryOnException(function() {
    // 你的数据库操作逻辑
}, 3, [\Illuminate\Database\QueryException::class, \PDOException::class], 500);

这样你就拥有了一个既贴合原始需求,又能灵活扩展的复用工具啦。

内容的提问来源于stack exchange,提问作者Muhammad Ahsan Abrar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:05:16