Prevent Race Conditions with Row Locking
Avoid overselling inventory and double-updates using transactions and lockForUpdate().
Brandon Hayes
October 18, 2025
2.4k114
Race conditions happen when two requests try to update the same record at the same time.
Example: two customers buy the last item.
- Both requests read stock=1
- Both reduce stock to 0
- Result: you oversold
## Safe pattern: lock the row
```php
use Illuminate\Support\Facades\DB;
DB::transaction(function () use ($productId) {
$product = DB::table('products')
->where('id', $productId)
->lockForUpdate()
->first();
if ($product->stock <= 0) {
throw new Exception('Out of stock');
}
DB::table('products')
->where('id', $productId)
->update(['stock' => $product->stock - 1]);
});
```
## Sequence: how locking prevents conflicts
```mermaid
sequenceDiagram
participant A as Request A
participant DB as Database
participant B as Request B
A->>DB: lockForUpdate(product)
DB-->>A: row locked, stock=1
B->>DB: lockForUpdate(product)
DB-->>B: waits (locked)
A->>DB: update stock=0
A->>DB: commit (unlock)
DB-->>B: lock granted, stock=0
```
In the next tutorial, we will learn indexing to speed up queries.
#Laravel#Database#Performance#Advanced