- Laravel
- database
- concurrency
Let DB::transaction() retry a deadlock
The second argument of DB::transaction() is the number of attempts: a deadlock is retried that many times before the exception reaches you.
1 min read
Under load, two transactions that touch the same rows in a different order deadlock, and the database kills one of them. MySQL's answer is "retry it", and Laravel can do that for you.
DB::transaction(function () use ($order) {
$order->lockForUpdate()->first()->decrementStock();
Payment::create([...]);
}, attempts: 3);On a deadlock error the closure runs again, up to three times, with a fresh transaction each time. Keep the closure free of side effects that must not repeat (an email, an HTTP call); queue those after the transaction with DB::afterCommit() or dispatch(...)->afterCommit().
Other exceptions are not retried, only the database's deadlock signal.