Transactions and locks

DB::transaction

The transaction method runs a closure inside one database transaction. If the closure finishes, Laravel commits everything, and if it throws, every change rolls back together.

use Illuminate\Support\Facades\DB; DB::transaction(function () use ($order) { $order->update(["status" => "paid"]); });

Manual control

Long or branching flows may need explicit control instead of a closure. Begin the transaction by hand, commit on success, and roll back inside the catch block on any failure.

use Illuminate\Support\Facades\DB; try { DB::beginTransaction(); DB::commit(); } catch (Throwable $e) { DB::rollBack(); }

Lock rows

Two requests can read the same balance before either writes, which loses one update. The lockForUpdate method locks the selected rows until the transaction ends, forcing the second reader to wait.

use Illuminate\Support\Facades\DB; $user = DB::table("users") ->where("id", 1) ->lockForUpdate() ->first();

Retry note

Locked rows can deadlock when two transactions wait on each other, so the database kills one of them. Pass an attempt count as the second argument and Laravel retries the closure that many times.

use Illuminate\Support\Facades\DB; DB::transaction(function () use ($order) { $order->update(["status" => "paid"]); }, 3);

Next: Deployment

Article author: Arthur Isaev