🧩 Implemented Deadlock Handling in Database Transactions
Implemented Deadlock Handling in Laravel Database Transactions | Laravel Tips
Learn how to handle database deadlocks in Laravel using DB::transaction() and lockForUpdate(). Ensure reliable concurrent updates with retry logic and error logging across MySQL, PostgreSQL, SQL Server, and more.
try {
DB::transaction(function () use ($userId, $recordId, $data) {
$row = DB::table('example_table')
->where('user_id', $userId)
->where('id', $recordId)
->lockForUpdate()
->first();
if ($row) {
DB::table('example_table')
->where('user_id', $userId)
->where('id', $recordId)
->update($data);
}
});
} catch (\Illuminate\Database\QueryException $e) {
if (in_array($e->getCode(), [40001, 1213, 1205])) {
sleep(2); // retry logic
// re-run the transaction
}
Log::error("Transaction failed: " . $e->getMessage());
}
In modern web applications, handling concurrent database operations efficiently is crucial. During simultaneous updates, a deadlock may occur when two or more transactions wait for each other to release locks, causing the system to halt.
To prevent this, I implemented a robust deadlock resolution mechanism in Laravel, using DB::transaction() along with lockForUpdate(). This approach ensures data consistency and reliability even under heavy concurrent load.
If a deadlock occurs, the system automatically retries the failed operation, logs the issue, and continues executing gracefully — maintaining stability without data loss.
Different databases return different error codes when a deadlock or locking issue occurs. Here are some common ones:
MySQL / MariaDB:
1213(Deadlock),1205(Lock wait timeout)SQL Standard:
40001(Serialization failure)PostgreSQL:
40P01(Deadlock detected)SQL Server:
1205(Deadlock victim),1222(Lock request timeout)
Understanding these codes helps in writing effective retry and error-handling logic.
This script useslockForUpdate() to prevent other transactions from modifying the same record until the current one finishes. If a deadlock is detected (based on error code), the script pauses for 2 seconds and retries, ensuring reliable transaction processing.Always use transactions when updating multiple related records.
Use
lockForUpdate()to ensure safe concurrent updates.
Implement retry logic for error codes related to deadlocks.
Log errors for debugging and system monitoring.
By handling deadlocks efficiently, applications can achieve high reliability, even under concurrent database loads — ensuring smooth and secure performance for end users.