• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Step-by-Step: Diagnosing Deadlocks on InnoDB row-level locking during simultaneous checkout writes on AWS Servers

Step-by-Step: Diagnosing Deadlocks on InnoDB row-level locking during simultaneous checkout writes on AWS Servers

Identifying the Problem: The Simultaneous Checkout Conundrum

A common and particularly thorny issue in e-commerce systems, especially those experiencing high concurrency, is the occurrence of deadlocks during the checkout process. When multiple users attempt to purchase the last few items of a popular product simultaneously, their transactions can contend for the same rows in the database. If not managed carefully, this contention can lead to InnoDB’s row-level locking mechanism triggering a deadlock, halting both transactions and frustrating customers. This post details a systematic approach to diagnosing and resolving such deadlocks on AWS-managed MySQL instances, focusing on practical, actionable steps.

Leveraging MySQL’s Information Schema for Deadlock Detection

The first line of defense in diagnosing deadlocks is to query MySQL’s `information_schema`. Specifically, the `INNODB_TRX` and `INNODB_LOCKS` tables provide invaluable insights into active transactions and the locks they hold. When a deadlock is suspected, these tables are your primary source of information.

To get a snapshot of currently running transactions and their states, execute the following query:

SELECT * FROM information_schema.INNODB_TRX;

This will show you transaction IDs, their start times, states (e.g., ‘RUNNING’, ‘LOCK WAIT’), and the transaction that is waiting for a lock. The key column here is `trx_mysql_thread_id`, which corresponds to the thread ID you’ll need to investigate further.

Next, to understand what locks are being held and requested, query `INNODB_LOCKS` and `INNODB_LOCK_WAITS`:

SELECT
    l.lock_id,
    l.lock_trx_id,
    l.lock_mode,
    l.lock_type,
    l.lock_data,
    lw.requesting_trx_id,
    lw.requested_lock_id,
    lw.requested_mode,
    lw.requested_type,
    lw.requested_data
FROM
    information_schema.INNODB_LOCKS l
LEFT JOIN
    information_schema.INNODB_LOCK_WAITS lw ON l.lock_id = lw.requested_lock_id
WHERE
    lw.requesting_trx_id IS NOT NULL;

This query reveals which transaction (`requesting_trx_id`) is waiting for a lock held by another transaction (`lock_trx_id`). The `lock_data` column is crucial, as it often contains the primary key of the row involved in the lock contention. In a checkout scenario, this will typically be the `product_id` or `order_item_id`.

Analyzing the InnoDB Deadlock Log

While `information_schema` provides a real-time view, MySQL also logs deadlocks when they occur. This log is invaluable for post-mortem analysis. To enable deadlock logging, you need to set the `innodb_print_all_deadlocks` variable to `ON` in your MySQL configuration.

On AWS RDS, this is typically done by modifying the database instance’s parameter group. Create a new parameter group or modify an existing one, and set `innodb_print_all_deadlocks` to `1`. Then, associate this parameter group with your RDS instance and reboot it for the changes to take effect.

The deadlock information will be written to the MySQL error log. On AWS RDS, you can access these logs via the AWS Management Console (RDS -> Databases -> Select your instance -> Logs & events -> Log files) or by using the AWS CLI:

aws rds describe-db-logs --db-instance-identifier your-db-instance-id --log-type error --output text --query "லாக்ஸ்[*].logFileName" | xargs -I {} aws rds download-db-log-file-portion --db-instance-identifier your-db-instance-id --log-file-name {} --output text

Search the error log for entries containing “LATEST DETECTED DEADLOCK”. The output is verbose and includes:

  • The transactions involved.
  • The SQL statements being executed by each transaction.
  • The locks held and requested by each transaction.
  • The order in which locks were acquired, which is key to understanding the circular dependency.

Example snippet from a deadlock log:

2023-10-27 10:30:00 12345 [Note] InnoDB: LATEST DETECTED DEADLOCK
---------------------
2023-10-27 10:30:00 12345 [Note] InnoDB: Transaction information:
Transaction 1001, ACTIVE 0 sec, idle 0 sec, ...
 transaction rollback
...
Transaction 1002, ACTIVE 0 sec, idle 0 sec, ...
 transaction rollback
...
---TRANSACTION 1001---
...
 lock_id = 1002 10000000000000000000, lock_mode = X locks rec but not gap
 lock_data = {
    "table": "products",
    "index": "PRIMARY",
    "values": [123]
}
...
---TRANSACTION 1002---
...
 lock_id = 1003 10000000000000000000, lock_mode = X locks rec but not gap
 lock_data = {
    "table": "products",
    "index": "PRIMARY",
    "values": [456]
}
...
---WAITING FOR LOCK---
Transaction 1001:
 lock_id = 1003 10000000000000000000, lock_mode = X locks rec but not gap
 lock_data = {
    "table": "products",
    "index": "PRIMARY",
    "values": [456]
}
...
Transaction 1002:
 lock_id = 1002 10000000000000000000, lock_mode = X locks rec but not gap
 lock_data = {
    "table": "products",
    "index": "PRIMARY",
    "values": [123]
}
...

In this example, Transaction 1001 is trying to acquire an X lock on `products` row with PRIMARY key `456`, but it’s held by Transaction 1002. Simultaneously, Transaction 1002 is trying to acquire an X lock on `products` row with PRIMARY key `123`, which is held by Transaction 1001. This circular dependency is the deadlock.

Strategies for Resolving Deadlocks

Once the cause is identified, several strategies can be employed to mitigate or resolve deadlocks:

1. Optimizing Transaction Order

The most effective solution is often to ensure that all transactions accessing the same set of resources do so in a consistent order. In the checkout scenario, this means always updating product stock and creating order items in the same sequence. If both transactions try to update product A then product B, a deadlock is less likely than if one tries A then B, and the other tries B then A.

Consider a scenario where you have a `products` table and an `orders` table. A typical checkout process might involve:

  • Decrementing product stock (e.g., `UPDATE products SET stock = stock – 1 WHERE id = ? AND stock > 0`).
  • Inserting into the `orders` table.
  • Inserting into the `order_items` table.

If multiple checkout processes are running concurrently, and they are processing items in different orders (e.g., one processes product ID 10 then 20, another processes 20 then 10), deadlocks can occur. The solution is to always process product IDs in ascending order within a single transaction.

// Example PHP pseudocode for consistent ordering
function processCheckout(userId, items) {
    // Sort items by product ID to ensure consistent lock acquisition order
    usort($items, function($a, $b) {
        return $a['productId'] <=> $b['productId'];
    });

    $db->beginTransaction();
    try {
        foreach ($items as $item) {
            $productId = $item['productId'];
            $quantity = $item['quantity'];

            // 1. Decrement stock - ensure consistent order by product ID
            $stmt = $db->prepare("UPDATE products SET stock = stock - ? WHERE id = ? AND stock >= ?");
            $stmt->execute([$quantity, $productId, $quantity]);

            if ($stmt->rowCount() === 0) {
                throw new Exception("Insufficient stock for product {$productId}");
            }

            // 2. Add to order items (or equivalent)
            // ...
        }
        // 3. Create order
        // ...
        $db->commit();
    } catch (Exception $e) {
        $db->rollBack();
        // Log error, handle retry, etc.
        throw $e;
    }
}

2. Reducing Transaction Scope and Duration

Long-running transactions increase the window of opportunity for deadlocks. Analyze your checkout logic and identify any operations that can be moved outside the critical transaction block. For instance, sending confirmation emails or updating external inventory systems should ideally happen after the database transaction has successfully committed.

Minimize the number of queries within a transaction. Ensure that only essential database operations that require atomicity are included. Avoid fetching large datasets or performing complex calculations within the transaction itself.

3. Using Appropriate Isolation Levels

While `REPEATABLE READ` is the default for InnoDB and generally provides good consistency, in some high-concurrency scenarios, it might be too restrictive. Consider if `READ COMMITTED` could be a viable alternative. `READ COMMITTED` uses row locks only when data is modified, and for reads, it uses a consistent snapshot of the data as it existed when the statement began. This can reduce lock contention but might introduce non-repeatable reads or phantom reads, which need to be carefully evaluated for your specific application logic.

To change the isolation level for a session:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

Or, to change it globally (requires `SUPER` privilege and affects all new connections):

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

On AWS RDS, you can set the default isolation level for new connections by modifying the `transaction_isolation` parameter in your DB parameter group.

4. Implementing Retry Logic

Even with optimizations, deadlocks can still occur under extreme load. A robust application should be designed to handle them gracefully. When a deadlock is detected (either by catching a specific MySQL error code like `1213` or by observing transaction states in `information_schema`), the application should roll back the current transaction and retry it after a short, randomized delay. This is often the most practical approach for high-traffic systems.

// Example PHP retry logic
function executeWithRetry($db, $sql, $params, $maxRetries = 3, $delayMs = 100) {
    $retries = 0;
    while ($retries <= $maxRetries) {
        try {
            $db->beginTransaction();
            // Execute your SQL statements here...
            // e.g., $stmt = $db->prepare($sql); $stmt->execute($params);
            $db->commit();
            return true; // Success
        } catch (PDOException $e) {
            $db->rollBack();
            if ($e->getCode() == '40001' || strpos($e->getMessage(), 'deadlock') !== false) { // MySQL error code 1213 for deadlock
                $retries++;
                if ($retries > $maxRetries) {
                    error_log("Max retries reached for query: {$sql}. Error: {$e->getMessage()}");
                    throw $e; // Re-throw after max retries
                }
                $delay = $delayMs * pow(2, $retries) + mt_rand(0, $delayMs); // Exponential backoff with jitter
                usleep($delay * 1000); // Sleep in microseconds
                error_log("Deadlock detected. Retrying query ({$retries}/{$maxRetries})...");
            } else {
                throw $e; // Re-throw other errors
            }
        }
    }
}

Monitoring and Prevention

Beyond immediate diagnosis, continuous monitoring is key. Set up alerts for high numbers of deadlocks reported in the MySQL error logs or for transactions stuck in a ‘LOCK WAIT’ state in `information_schema.INNODB_TRX`. Regularly review your application’s transaction patterns, especially around critical user flows like checkout, and proactively identify potential concurrency issues before they manifest as production incidents.

By combining detailed analysis of MySQL’s internal diagnostics with sound architectural practices like consistent transaction ordering and robust error handling, you can effectively combat the elusive deadlock problem in high-concurrency environments.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 100 SEO and Schema Markup Plugins for Headless Decoupled Sites for Independent Web Developers and Indie Hackers
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers that Will Dominate the Software Industry in 2026
  • Top 5 SEO Growth Tactics to Explode Search Engine Visibility for SaaS to Boost Organic Search Growth by 200%

Categories

  • apache (1)
  • Business & Monetization (378)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (484)
  • DevOps (7)
  • DevOps & Cloud Scaling (918)
  • Django (1)
  • Migration & Architecture (66)
  • MySQL (1)
  • Performance & Optimization (626)
  • PHP (5)
  • Plugins & Themes (88)
  • Security & Compliance (524)
  • SEO & Growth (421)
  • Server (23)
  • Ubuntu (9)
  • WordPress (22)
  • WordPress Plugin Development (7)

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 100 SEO and Schema Markup Plugins for Headless Decoupled Sites for Independent Web Developers and Indie Hackers
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers that Will Dominate the Software Industry in 2026
  • Top 5 SEO Growth Tactics to Explode Search Engine Visibility for SaaS to Boost Organic Search Growth by 200%
  • Top 100 Premium Newsletter and Subscription Business Models for Devs to Scale to $10,000 Monthly Recurring Revenue (MRR)

Top Categories

  • DevOps & Cloud Scaling (918)
  • Performance & Optimization (626)
  • Security & Compliance (524)
  • Debugging & Troubleshooting (484)
  • SEO & Growth (421)
  • Business & Monetization (378)

Our Products

  • School Management & Student Administration System
  • Integrated Hospital & Clinic Management System
  • Real Estate Directory & Agent Portal
  • Restaurant POS & Table Booking System
  • Retail Inventory POS & Billing System
  • Pharmacy Inventory & Clinic Billing System

Our Services

  • Vibe Engineering & AI Code Auditing Services
  • Prompt Engineering & "Vibe Coding" Workflow Consulting
  • AI-Augmented "Vibe Coding" & Rapid MVP Development
  • Figma to Shopify Liquid Theme Customization
  • Figma to WooCommerce Frontend Development
  • Figma to Magento 2 Theme Development

Copyright © 2026 · Vinay Vengala