Imagine this:
A user clicks the "Pay Now" button twice.
Or two requests hit your API at the exact same time.
Without proper protection, you might:
❌ Charge the customer twice.
❌ Create duplicate orders.
❌ Oversell inventory.
❌ Corrupt important data.
Many developers try to solve this with:
JavaScript button disabling
Validation rules
Unique checks
These improve the user experience—but they don't solve concurrency.
A better solution is to combine Laravel's database transactions with locking.
DB::transaction(function () use ($orderId) {
$order = Order::where('id', $orderId)
->lockForUpdate()
->first();
if ($order->status !== 'pending') {
return;
}
$order->update([
'status' => 'paid',
]);
});
lockForUpdate() ensures that while one request is processing the order, every other concurrent request waits until the transaction completes.
For distributed systems, Laravel also provides cache locks:
Cache::lock("order:{$orderId}", 10)->block(5, function () {
// Process payment safely
});
The biggest lesson?
Validation protects your inputs.
Locks protect your data.
Knowing when to use each is what separates production-ready applications from applications that only work in development.
What's your preferred strategy for handling race conditions in Laravel?
Top comments (0)