Menu

🧩 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 uses lockForUpdate() 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.

Flow-chart laravel

Contact