PHP cookbook · Advanced
Retry deadlocked transactions in PHP
Handle deadlocks and serialization failures gracefully in high-concurrency write paths.
Approach
Deadlocks and serialization failures are normal under concurrency; the database aborts one transaction, which can be safely retried. Wrap the unit of work in a helper that retries a few times with jittered backoff on specific SQLSTATE codes (40001 serialization failure, 40P01 PostgreSQL deadlock; MySQL reports deadlocks as 40001/error 1213).
Solution
<?php
declare(strict_types=1);
/**
* @template T
* @param callable(PDO): T $work
* @return T
*/
function transactional(PDO $pdo, callable $work, int $maxAttempts = 3): mixed
{
for ($attempt = 1; ; $attempt++) {
$pdo->beginTransaction();
try {
$result = $work($pdo);
$pdo->commit();
return $result;
} catch (PDOException $e) {
$pdo->rollBack();
$retryable = in_array($e->getCode(), ['40001', '40P01'], true);
if (!$retryable || $attempt >= $maxAttempts) {
throw $e;
}
usleep(random_int(20_000, 100_000) * $attempt); // jittered backoff
} catch (Throwable $e) {
$pdo->rollBack();
throw $e;
}
}
}
$orderId = transactional($pdo, function (PDO $pdo) use ($cart) {
reserveStock($pdo, $cart);
return createOrder($pdo, $cart);
});
Pitfalls
- Retrying work with external side effects (emails, charges) inside the closure.
- Retrying forever.
- Not reducing deadlock likelihood: lock rows in a consistent order, keep transactions short.
Variations
- Doctrine DBAL:
$connection->transactional()plus catchingRetryableException. - Laravel:
DB::transaction(fn () => ..., attempts: 3).
Further reading: PostgreSQL: Serialization failure handling
Reference: https://www.postgresql.org/docs/current/mvcc-serialization-failure-handling.html
More PHP recipes
- Add CSRF protection to PHP forms
- Add health check endpoints to a PHP app
- Add structured logging with request IDs in PHP
- Build a secure password reset flow in PHP
- Cache expensive queries with Redis in PHP
- Call external APIs with timeouts and retries in PHP
- Handle file uploads securely in PHP
- Implement rate limiting in a PHP API