本文目录导读:

在 Laravel 中配置死锁重试,主要有以下几种方式:
使用 Laravel 内置重试机制
数据库配置方式(推荐)
在 config/database.php 中配置:
'mysql' => [
'driver' => 'mysql',
// ... 其他配置
'options' => [
PDO::ATTR_EMULATE_PREPARES => true,
],
'retry_after' => 100, // 毫秒
'max_retries' => 3, // 最大重试次数
],
队列任务重试
对于队列任务,在 config/queue.php 中配置:
'connections' => [
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
'after_commit' => true,
],
],
代码层面手动重试
使用 DB::transaction() 方法
use Illuminate\Support\Facades\DB;
use Illuminate\Database\QueryException;
try {
$result = DB::transaction(function () {
// 你的数据库操作
DB::table('users')->where('id', 1)->update(['name' => 'New Name']);
DB::table('orders')->insert([...]);
return $result;
}, 3); // 第三个参数是重试次数
} catch (QueryException $e) {
if ($e->getCode() == '40001' || str_contains($e->getMessage(), 'deadlock')) {
// 处理死锁异常
}
}
自定义重试逻辑
use Illuminate\Support\Facades\DB;
function retryOnDeadlock(callable $callback, int $maxAttempts = 3, int $delay = 100)
{
$attempts = 0;
while ($attempts < $maxAttempts) {
try {
return DB::transaction($callback);
} catch (\Illuminate\Database\QueryException $e) {
$attempts++;
// 检查是否是死锁
if ($this->isDeadlock($e)) {
if ($attempts >= $maxAttempts) {
throw $e;
}
usleep($delay * 1000); // 转换为微秒
continue;
}
throw $e;
}
}
}
private function isDeadlock(QueryException $e)
{
$message = $e->getMessage();
return str_contains($message, 'Deadlock') ||
str_contains($message, 'deadlock') ||
$e->getCode() == '40001' ||
$e->getCode() == '1213';
}
// 使用
retryOnDeadlock(function () {
// 数据库操作
});
使用 Laravel 的重试中间件
创建重试中间件
namespace App\Http\Middleware;
use Closure;
use Illuminate\Database\QueryException;
class RetryOnDeadlock
{
public function handle($request, Closure $next, $maxRetries = 3, $delay = 100)
{
$attempts = 0;
do {
try {
return $next($request);
} catch (QueryException $e) {
$attempts++;
if ($attempts >= $maxRetries) {
throw $e;
}
if ($this->isDeadlock($e)) {
usleep($delay * 1000);
continue;
}
throw $e;
}
} while (true);
}
private function isDeadlock($e)
{
return str_contains($e->getMessage(), 'Deadlock') ||
$e->getCode() == '1213';
}
}
注册中间件:
// app/Http/Kernel.php
protected $routeMiddleware = [
'retry' => \App\Http\Middleware\RetryOnDeadlock::class,
];
// 在路由中使用
Route::post('/update-data', function () {
// 数据库操作
})->middleware('retry:3,200');
使用第三方包
laravel-db-deadlock-retry
composer require beyondcode/laravel-db-deadlock-retry
安装后自动启用,无需额外配置。
最佳实践建议
完整的重试策略示例
use Illuminate\Support\Facades\DB;
use Illuminate\Database\QueryException;
class DatabaseService
{
const MAX_RETRIES = 3;
const BASE_DELAY = 100; // 毫秒
public function executeWithRetry(callable $callback)
{
$attempts = 0;
while (true) {
try {
return DB::transaction($callback);
} catch (QueryException $e) {
$attempts++;
if (!$this->isDeadlock($e) || $attempts >= self::MAX_RETRIES) {
throw $e;
}
// 指数退避
$delay = self::BASE_DELAY * pow(2, $attempts - 1);
usleep($delay * 1000);
// 记录重试日志
\Log::warning('数据库死锁,正在重试', [
'attempt' => $attempts,
'delay' => $delay,
]);
}
}
}
private function isDeadlock(QueryException $e)
{
return in_array($e->getCode(), ['40001', '1213']) ||
preg_match('/deadlock/i', $e->getMessage());
}
}
使用:
$service = new DatabaseService();
$result = $service->executeWithRetry(function () {
// 数据库操作
});
注意事项
- 不要过度重试:建议最多重试 3-5 次
- 使用指数退避:每次重试间隔时间递增
- 记录日志:记录重试情况便于排查问题
- 幂等设计:确保重试操作是幂等的
- 监控告警:监控死锁频率,及时发现系统问题
选择哪种方式取决于你的具体需求,对于大多数情况,使用 Laravel 内置的 DB::transaction() 方法并指定重试次数就足够了。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播