Locks, Deadlocks, and Concurrent Database Access in MySQL
Course: MySQL Training Course
Topic: Locks, Deadlocks, and Concurrent Database Access
Course Link: MySQL Training Course at JustAcademy
Demo Link: Register for a Course Demo
1. Introduction to Locks, Deadlocks, and Concurrent Database Access
MySQL databases often serve multiple users and applications simultaneously. For example, one user may update a customer's address while another user processes an order for the same customer. At the same time, another application may generate a report that reads the same records.
When multiple transactions access or modify the same data, the database must coordinate their operations to maintain data consistency. MySQL uses locking mechanisms, transaction isolation, and concurrency control to manage these situations.
Three important concepts are locks, deadlocks, and concurrent database access. Locks help coordinate access to shared data. Deadlocks occur when transactions wait on one another in a circular dependency. Concurrent database access refers to multiple transactions executing during overlapping periods.
Learning Objectives
- Understand concurrent database access and why it is necessary.
- Learn how database locks protect data consistency.
- Differentiate shared locks and exclusive locks.
- Understand row-level, table-level, and intention locks.
- Learn how InnoDB handles locking and concurrent transactions.
- Understand deadlocks, their causes, and their effects.
- Identify blocking transactions and investigate lock waits.
- Use SQL commands such as SELECT FOR UPDATE and SELECT FOR SHARE.
- Apply techniques to prevent and resolve deadlocks.
- Follow best practices for high-concurrency database applications.
2. What Is Concurrent Database Access?
Concurrent database access occurs when two or more transactions access a database during overlapping periods. The transactions may read different records, read the same records, or attempt to modify the same data.
Concurrency allows databases to serve many users efficiently without requiring every transaction to wait for all other transactions to finish. However, simultaneous operations must be coordinated to prevent incorrect results and conflicting changes.
2.1 Example of Concurrent Access
Suppose a product has 10 units in stock. Two customers attempt to purchase 7 units each at nearly the same time.
| Transaction |
Operation |
Potential Problem |
| Transaction A |
Reads stock quantity as 10. |
Assumes 10 units are available. |
| Transaction B |
Reads stock quantity as 10. |
Also assumes 10 units are available. |
| Transaction A |
Reduces stock by 7. |
Attempts to leave 3 units. |
| Transaction B |
Reduces stock by 7. |
Could produce an incorrect result if the application does not coordinate updates correctly. |
Appropriate locking and atomic updates help ensure that the database does not sell more units than are available. The exact result depends on the transaction logic, isolation level, constraints, and locking behavior.
2.2 Benefits of Concurrent Access
- Supports many users at the same time.
- Improves resource utilization.
- Allows read and write operations to overlap when permitted.
- Helps applications handle large numbers of transactions.
- Improves responsiveness when transactions do not unnecessarily block one another.
2.3 Challenges of Concurrent Access
- Two transactions may attempt to update the same record.
- A transaction may wait for a lock held by another transaction.
- Transactions can encounter deadlocks.
- Long-running transactions may reduce application performance.
- Incorrect application logic can produce lost updates or inconsistent business results.
3. What Is a Database Lock?
A database lock is a mechanism that controls access to a database resource while a transaction performs an operation. A lock may protect a row, a range of index records, a table, or another database resource, depending on the storage engine and operation.
In MySQL, the InnoDB storage engine uses several types of locks to coordinate concurrent transactions. Locks help ensure that transactions follow the database's concurrency rules and prevent conflicting operations from proceeding in an unsafe manner.
3.1 Why Are Locks Required?
- To coordinate simultaneous updates to the same data.
- To protect changes until a transaction commits or rolls back.
- To prevent certain conflicting reads and writes.
- To support transaction isolation.
- To maintain consistency during operations such as transfers, payments, and inventory updates.
3.2 Simple Locking Example
Consider a bank account with a balance of ₹10,000. Transaction A starts a withdrawal while Transaction B attempts to withdraw money from the same account. A lock can make Transaction B wait until Transaction A finishes the conflicting operation.
START TRANSACTION;
SELECT account_id, balance
FROM accounts
WHERE account_id = 1
FOR UPDATE;
UPDATE accounts
SET balance = balance - 1000
WHERE account_id = 1;
COMMIT;
The FOR UPDATE locking read requests exclusive locks on the applicable records. For an indexed lookup that identifies one InnoDB row, this typically locks the matching record, although the exact lock scope depends on the query, indexes, isolation level, and execution plan.
4. Types of Locks in MySQL
MySQL uses different locking mechanisms depending on the storage engine and the type of operation being performed.
4.1 Shared Lock (S Lock)
A shared lock permits a transaction to read a locked record while preventing conflicting modifications that require an exclusive lock. Multiple transactions can generally hold compatible shared locks on the same record.
In InnoDB, a locking read can request a shared lock using FOR SHARE.
START TRANSACTION;
SELECT *
FROM employees
WHERE employee_id = 101
FOR SHARE;
COMMIT;
This requests shared locks on the records examined by the locking read. Other transactions may be able to obtain compatible shared locks, but a conflicting update may need to wait.
4.2 Exclusive Lock (X Lock)
An exclusive lock is used when a transaction needs to modify a record. It prevents other transactions from acquiring incompatible locks on the same record until the lock is released.
START TRANSACTION;
SELECT *
FROM employees
WHERE employee_id = 101
FOR UPDATE;
UPDATE employees
SET salary = salary + 2000
WHERE employee_id = 101;
COMMIT;
The locking read requests an exclusive lock on the applicable records. The subsequent UPDATE changes the salary, and COMMIT completes the transaction.
4.3 Shared Lock vs. Exclusive Lock
| Feature |
Shared Lock |
Exclusive Lock |
| Purpose |
Coordinates locking reads. |
Protects records that a transaction intends to modify. |
| Compatible shared locks |
Generally allowed. |
Not compatible with another shared lock on the same record. |
| Conflicting modifications |
Can cause an update to wait. |
Can block other conflicting reads or writes that request locks. |
| Common SQL example |
SELECT ... FOR SHARE |
SELECT ... FOR UPDATE |
| Typical use |
Locking data that must be read consistently before a decision. |
Reading and then safely modifying selected records. |
4.4 Row-Level Locks
Row-level locking allows InnoDB to lock individual index records or related index ranges rather than locking an entire table for every modification. This can improve concurrency because transactions working on unrelated records may proceed at the same time.
START TRANSACTION;
UPDATE employees
SET salary = salary + 1000
WHERE employee_id = 101;
COMMIT;
If the query uses a suitable index to find employee 101, the update normally locks the relevant record rather than every row in the table. Additional locks may be taken depending on the query and isolation level.
4.5 Table-Level Locks
A table-level lock applies to a table as a whole. Table locks can be used explicitly with SQL statements such as LOCK TABLES, and some storage engines or operations use table-level locking behavior.
LOCK TABLES employees READ;
SELECT * FROM employees;
UNLOCK TABLES;
This example requests a read lock on the table for the current session. Explicit table locking has important interaction rules with transactions and storage engines. Use it carefully and consult the MySQL documentation for the installed version.
4.6 Intention Locks
InnoDB uses intention locks to indicate that a transaction intends to acquire shared or exclusive locks on records within a table. These locks help coordinate row-level locking with certain table-level locking operations.
The main intention lock types are:
- IS (Intention Shared): Indicates an intention to acquire shared locks on records in the table.
- IX (Intention Exclusive): Indicates an intention to acquire exclusive locks on records in the table.
Intention locks are generally managed automatically by InnoDB rather than manually created by application developers.
4.7 Record Locks
A record lock protects an index record. InnoDB uses indexes as part of its locking implementation, so the index and execution plan can influence which records are locked.
4.8 Gap Locks
A gap lock protects a gap between index records, or a gap before the first or after the last index record. Gap locking can prevent other transactions from inserting records into the protected gap under the applicable isolation and query conditions.
4.9 Next-Key Locks
A next-key lock combines a record lock with a lock on the gap preceding that index record. InnoDB may use next-key locks to help prevent certain phantom rows under its default REPEATABLE READ isolation level.
| Lock Type |
Purpose |
Typical Context |
| Record lock |
Protects an index record. |
Updating or locking a matching row. |
| Gap lock |
Protects a gap in an index. |
Preventing inserts into certain index ranges. |
| Next-key lock |
Protects a record and the preceding gap. |
Range locking under applicable InnoDB isolation behavior. |
| Intention lock |
Signals planned row-level locking within a table. |
Coordination between row and table locking. |
5. How InnoDB Manages Locks
InnoDB is MySQL's main transactional storage engine. It combines multi-version concurrency control (MVCC) with locking mechanisms to support concurrent reads and writes.
5.1 Multi-Version Concurrency Control (MVCC)
MVCC allows certain read operations to access a consistent version of data without always needing to wait for a transaction that is modifying the same records. InnoDB maintains information that allows consistent reads to reconstruct earlier versions of rows when necessary.
For example, a normal SELECT under a suitable isolation level can often read a consistent snapshot while another transaction has an uncommitted update. This is different from a locking read such as SELECT FOR UPDATE.
5.2 Consistent Reads and Locking Reads
| Read Type |
Example |
General Behavior |
| Consistent read |
SELECT * FROM employees; |
Typically reads a consistent snapshot without locking every row against updates. |
| Shared locking read |
SELECT * FROM employees WHERE employee_id = 101 FOR SHARE; |
Requests shared locks on applicable records. |
| Exclusive locking read |
SELECT * FROM employees WHERE employee_id = 101 FOR UPDATE; |
Requests exclusive locks on applicable records. |
The precise behavior depends on the isolation level, transaction state, query plan, and storage engine. A regular SELECT is not equivalent to a locking read.
5.3 Transaction Duration and Lock Duration
For many InnoDB operations, locks acquired by a transaction are retained until the transaction commits or rolls back. Some statement-level and special locking behavior can differ, so applications should not assume that every lock has exactly the same lifetime.
Long transactions can keep locks for longer periods, increasing the likelihood of blocking and deadlocks. Keeping transactions short is an important performance and reliability practice.
6. What Is a Deadlock?
A deadlock occurs when two or more transactions wait for resources held by one another, creating a circular waiting condition. None of the involved transactions can proceed without another transaction releasing a required lock.
InnoDB detects deadlocks and normally resolves them by rolling back one transaction, known as the deadlock victim. The other transaction can then continue if its remaining operations are valid.
6.1 Simple Deadlock Example
Assume two bank accounts exist: account 1 and account 2.
- Transaction A locks account 1 and then requests a lock on account 2.
- Transaction B locks account 2 and then requests a lock on account 1.
- Transaction A waits for Transaction B to release account 2.
- Transaction B waits for Transaction A to release account 1.
This creates a circular wait. InnoDB can detect the deadlock and roll back one of the transactions so that the other can proceed.
6.2 Deadlock Sequence
| Step |
Transaction A |
Transaction B |
| 1 |
Locks account 1. |
Locks account 2. |
| 2 |
Requests account 2 and waits. |
Holds account 2. |
| 3 |
Waiting for Transaction B. |
Requests account 1 and waits. |
| 4 |
Waiting for Transaction B. |
Waiting for Transaction A. |
| 5 |
InnoDB detects the deadlock and rolls back one transaction. |
7. Deadlock vs. Lock Wait
A deadlock and a lock wait are related but different problems.
| Feature |
Deadlock |
Lock Wait |
| Definition |
Transactions form a circular dependency. |
A transaction waits for a conflicting lock held by another transaction. |
| Can the transaction eventually proceed? |
Not without resolving the circular wait. |
Usually, if the blocking transaction releases the lock. |
| Typical resolution |
InnoDB detects the deadlock and rolls back a victim transaction. |
The blocking transaction finishes, or the waiting operation times out or is cancelled. |
| Common diagnostic |
Deadlock details from InnoDB. |
Performance Schema lock-wait information and timeout errors. |
A lock wait does not automatically mean a deadlock exists. A transaction may be waiting for another transaction that is performing a valid, long-running operation.
8. Common Causes of Deadlocks
8.1 Updating Records in Different Orders
Two transactions may update the same records in opposite orders. One locks record A before record B, while the other locks record B before record A. If both transactions hold their first lock while requesting the second, a deadlock can occur.
8.2 Long-Running Transactions
Transactions that remain open for a long time can hold locks while performing additional work. This increases the time during which other transactions can become blocked.
8.3 Missing or Inefficient Indexes
If a query lacks a suitable index, MySQL may need to examine many records. The resulting locking footprint can be larger than expected for a locking read or modification statement.
8.4 High Concurrent Update Activity
When many sessions frequently update the same rows or overlapping ranges, lock contention and deadlock risk increase.
8.5 Range-Based Operations
Range queries and modifications can involve several index records and, depending on isolation and query conditions, gaps between records. Overlapping ranges can increase the possibility of lock conflicts.
8.6 Inconsistent Application Workflows
If different application functions access shared tables or rows in different sequences, they can create circular dependencies. Consistent access ordering helps reduce this risk.
9. Demonstrating Locking with Two MySQL Sessions
The following exercise demonstrates how one transaction can block another. Open two separate database connections, called Session A and Session B. Run the statements in the specified order.
9.1 Prepare the Test Table
CREATE TABLE IF NOT EXISTS lock_demo (
id INT PRIMARY KEY,
item_name VARCHAR(100),
quantity INT NOT NULL
) ENGINE = InnoDB;
INSERT INTO lock_demo (id, item_name, quantity)
VALUES (1, 'Keyboard', 10)
ON DUPLICATE KEY UPDATE
item_name = VALUES(item_name);
9.2 Session A: Lock the Record
START TRANSACTION;
SELECT *
FROM lock_demo
WHERE id = 1
FOR UPDATE;
Session A obtains an exclusive lock on the matching record and keeps the transaction open.
9.3 Session B: Attempt to Update the Same Record
START TRANSACTION;
UPDATE lock_demo
SET quantity = quantity - 1
WHERE id = 1;
Session B will normally wait because Session A holds a conflicting lock on the record.
9.4 Session A: Release the Lock
COMMIT;
Once Session A commits, Session B can usually continue if no other blocking condition exists. Session B must then finish its own transaction:
COMMIT;
9.5 Key Learning
- Locks coordinate conflicting modifications.
- Transactions can remain blocked while waiting for a lock.
- COMMIT or ROLLBACK releases transactional locks when the transaction ends.
- Leaving transactions open unnecessarily can reduce concurrency.
10. Demonstrating a Deadlock with Two Sessions
This exercise demonstrates the basic pattern that can create a deadlock. Use a test database only, because InnoDB may automatically roll back one of the transactions.
10.1 Prepare Two Records
CREATE TABLE IF NOT EXISTS deadlock_demo (
id INT PRIMARY KEY,
amount INT NOT NULL
) ENGINE = InnoDB;
INSERT INTO deadlock_demo (id, amount)
VALUES (1, 100), (2, 200)
ON DUPLICATE KEY UPDATE
amount = VALUES(amount);
10.2 Session A: Lock the First Record
START TRANSACTION;
UPDATE deadlock_demo
SET amount = amount + 10
WHERE id = 1;
10.3 Session B: Lock the Second Record
START TRANSACTION;
UPDATE deadlock_demo
SET amount = amount + 20
WHERE id = 2;
10.4 Session A: Request the Second Record
UPDATE deadlock_demo
SET amount = amount + 1
WHERE id = 2;
Session A waits for Session B because Session B holds the lock on record 2.
10.5 Session B: Request the First Record
UPDATE deadlock_demo
SET amount = amount + 1
WHERE id = 1;
Session B now waits for Session A. If the circular wait is established, InnoDB normally detects the deadlock and rolls back one of the transactions. The statement that receives the error depends on the timing and which transaction is selected as the victim.
10.6 Important Notes
- Run the statements in two genuinely separate database sessions.
- Do not issue COMMIT before the second session requests the conflicting record.
- If InnoDB reports a deadlock, inspect the error and transaction state.
- After a deadlock error, the application should treat the affected transaction as failed and restart the complete logical transaction when appropriate.
- Exact outcomes depend on timing, server configuration, and execution order.
11. How to Prevent and Reduce Deadlocks
11.1 Access Records in a Consistent Order
One of the most effective techniques is to access shared records in the same order in every transaction. For example, if two account IDs are involved, lock the smaller ID first and the larger ID second in all related operations.
START TRANSACTION;
SELECT account_id, balance
FROM accounts
WHERE account_id = 1
FOR UPDATE;
SELECT account_id, balance
FROM accounts
WHERE account_id = 2
FOR UPDATE;
-- Perform validated updates here.
COMMIT;
This example illustrates a consistent order for two known accounts. For a general application, sort the account identifiers and acquire locks in that order, and ensure all relevant code paths follow the same rule.
11.2 Keep Transactions Short
- Perform necessary database work within the transaction.
- Avoid user interaction while a transaction is open.
- Avoid lengthy external API calls between locking reads and COMMIT.
- Commit or roll back as soon as the logical unit of work is complete.
11.3 Use Appropriate Indexes
Indexes can help MySQL locate records efficiently and reduce unnecessary scanning. Review indexes on columns used in WHERE clauses, JOIN conditions, and ordering operations that influence locking queries.
CREATE INDEX idx_orders_customer_id
ON orders(customer_id);
Only create indexes that fit the workload. Indexes improve some operations but also add storage costs and overhead to INSERT, UPDATE, and DELETE statements.
11.4 Update Only the Required Records
Use precise WHERE conditions so that statements modify only the intended rows.
UPDATE products
SET quantity = quantity - 1
WHERE product_id = 101
AND quantity > 0;
This statement combines the stock condition and decrement into one atomic database operation. The application should inspect the affected-row count to determine whether a unit was actually reserved. If a row was not changed, the application should handle the unavailable-stock case appropriately.
11.5 Avoid Unnecessary Locking Reads
Use SELECT FOR UPDATE or SELECT FOR SHARE only when the application requires locking behavior. A normal consistent SELECT is often sufficient for reporting and read-only display operations.
11.6 Handle Deadlocks with Retries
Deadlocks can occur even in carefully designed systems. Applications should be prepared to retry a complete transaction when MySQL reports a deadlock, provided that retrying is safe for the operation.
- Recognize the deadlock error, commonly MySQL error 1213 with SQLSTATE 40001.
- Discard assumptions based on the failed transaction's intermediate work.
- Start a new transaction and rerun the complete logical operation.
- Limit retry attempts and use a short backoff when appropriate.
- Ensure that external side effects, such as sending payment notifications, are not duplicated by retries.
12. Investigating Locks and Deadlocks
When an application becomes slow or reports transaction errors, database administrators can inspect lock information to identify blocking sessions and understand the cause.
12.1 View the Latest InnoDB Deadlock Information
SHOW ENGINE INNODB STATUS;
Review the output's LATEST DETECTED DEADLOCK section when available. It can show the transactions involved, the statements they executed, and the locks they held or requested.
The status output is a diagnostic snapshot. It may describe only the latest detected deadlock, so capture relevant details promptly when investigating recurring incidents.
12.2 Inspect Active Transactions
SELECT
trx_id,
trx_state,
trx_started,
trx_wait_started,
trx_mysql_thread_id,
trx_query
FROM information_schema.innodb_trx;
This query can show active InnoDB transactions and their state, start time, waiting time, connection thread ID, and current query when available. Access to some diagnostic information may require additional privileges.
12.3 Inspect Lock Waits Using Performance Schema
On MySQL versions that expose these Performance Schema tables, the following query can help identify relationships between waiting and blocking transactions.
SELECT
REQUESTING_ENGINE_TRANSACTION_ID AS waiting_trx_id,
REQUESTING_THREAD_ID AS waiting_thread_id,
BLOCKING_ENGINE_TRANSACTION_ID AS blocking_trx_id,
BLOCKING_THREAD_ID AS blocking_thread_id
FROM performance_schema.data_lock_waits;
The data_lock_waits table reports relationships between transactions waiting for locks and transactions blocking them. The exact diagnostic columns and available data depend on the MySQL version and configuration.
12.4 Inspect InnoDB Locks
SELECT *
FROM performance_schema.data_locks;
This query displays lock information exposed by Performance Schema. For large systems, filter the output by table, schema, or other relevant columns rather than retrieving every lock record.
12.5 General Diagnostic Workflow
- Identify the application request or SQL statement that is slow or failing.
- Check the MySQL error message for a deadlock or lock-wait timeout.
- Inspect active transactions and lock-wait information.
- Use SHOW ENGINE INNODB STATUS to review deadlock details.
- Check indexes, query plans, transaction duration, and record access order.
- Correct the underlying transaction logic where possible.
- Monitor the workload to verify whether contention decreases.
13. Understanding Lock-Wait Timeouts
A lock-wait timeout occurs when a transaction waits for a lock longer than the configured limit. This is different from a deadlock: a timeout does not necessarily indicate a circular dependency.
InnoDB uses the innodb_lock_wait_timeout setting to control how long many InnoDB lock waits can continue before timing out.
13.1 Check the Current Setting
SELECT @@SESSION.innodb_lock_wait_timeout;
13.2 Set a Session-Level Timeout
SET SESSION innodb_lock_wait_timeout = 30;
This sets the session's lock-wait timeout to 30 seconds, subject to the supported value range and server version.
Important: Increasing the timeout does not fix the underlying cause of blocking. It may simply make a waiting application request wait longer. Investigate why the blocking transaction is taking so long before changing timeout settings.
13.3 Difference Between Deadlock and Timeout Handling
- For a detected deadlock, InnoDB normally rolls back the entire transaction selected as the victim.
- For a lock-wait timeout, the default behavior generally rolls back the waiting statement, not necessarily the entire transaction, unless configuration or application behavior changes the outcome.
- Applications should handle both conditions explicitly and decide whether the entire logical transaction needs to be rolled back and retried.
14. Concurrent Updates and Lost Updates
A lost update can occur when two transactions read the same initial value and then overwrite one another's changes in a way that causes one update to be lost. The exact risk depends on the SQL statements and transaction isolation behavior.
14.1 Potentially Unsafe Application Pattern
Imagine a product quantity of 10. An application reads the quantity into application memory, subtracts one, and later writes the calculated value back. Two application requests can both read 10 and both attempt to write 9, even though two units were intended to be removed.
14.2 Prefer Atomic Updates
UPDATE products
SET quantity = quantity - 1
WHERE product_id = 101
AND quantity > 0;
This lets MySQL perform the conditional decrement as a single statement. The application should verify the affected-row count to confirm whether the update succeeded.
14.3 Use a Locking Read When Required
START TRANSACTION;
SELECT quantity
FROM products
WHERE product_id = 101
FOR UPDATE;
-- Application validates the quantity.
UPDATE products
SET quantity = quantity - 1
WHERE product_id = 101
AND quantity > 0;
COMMIT;
Use this pattern when the business logic needs to inspect the locked value before deciding what to do. In production, check the update result and roll back if validation fails. A single conditional UPDATE may be simpler when no additional decision-making is required.
15. Transaction Isolation and Concurrency
Transaction isolation levels influence which changes one transaction can observe while another transaction is running. They also affect locking behavior and the possibility of certain anomalies.
| Isolation Level |
General Behavior |
Concurrency Consideration |
| READ UNCOMMITTED |
Can permit dirty reads. |
Less restrictive read behavior, but weaker consistency. |
| READ COMMITTED |
Consistent reads see data committed before each read begins. |
Can reduce some gap-locking behavior compared with REPEATABLE READ, with exceptions. |
| REPEATABLE READ |
Repeated consistent reads in a transaction generally use the same snapshot. |
InnoDB uses next-key locking in applicable locking operations to prevent certain phantom inserts. |
| SERIALIZABLE |
Uses stricter rules to make transactions behave more like a serial execution. |
Can increase blocking and reduce concurrency. |
Isolation levels do not eliminate the need for correct transaction logic. Choose an isolation level based on the application's consistency requirements and performance characteristics, and test it under realistic concurrent workloads.
16. Locking and Index Design
Index design can strongly influence concurrency. InnoDB locks index records and, under some conditions, ranges of records. An inefficient query may examine more index records than expected and increase the scope of locking.
16.1 Example Without a Suitable Index
UPDATE orders
SET status = 'Processing'
WHERE customer_id = 5001;
If customer_id does not have a suitable index, MySQL may need to examine many rows to find matching orders. The locking footprint and execution cost can be larger than necessary.
16.2 Add an Appropriate Index When Justified
CREATE INDEX idx_orders_customer
ON orders(customer_id);
An index can improve lookup performance and help limit the records examined. Evaluate the table's existing indexes and query plan before creating an additional index.
16.3 Use EXPLAIN to Review Queries
EXPLAIN
UPDATE orders
SET status = 'Processing'
WHERE customer_id = 5001;
EXPLAIN support and output for data-modification statements depend on the MySQL version. Where supported, use it to inspect the execution plan. Otherwise, review the equivalent SELECT plan and use suitable performance diagnostics.
17. Deadlock Handling in Application Code
Applications must assume that deadlocks can happen under concurrent workloads, even when database code follows good practices. A robust application recognizes the error and retries safely when appropriate.
17.1 Recommended Handling Steps
- Begin a transaction.
- Perform all required database operations.
- Validate affected-row counts and business rules.
- Commit only when every required operation succeeds.
- If a deadlock occurs, treat the logical transaction as failed.
- Retry the complete transaction in a new transaction, with a bounded retry count.
- Log enough context to investigate repeated deadlocks.
17.2 Pseudocode Example
for attempt in retry_limit:
begin_transaction()
try:
perform_database_updates()
validate_results()
commit_transaction()
break
catch deadlock_error:
rollback_if_needed()
if attempt_is_last:
raise_error()
wait_for_short_backoff()
catch other_error:
rollback_if_needed()
raise_error()
This is illustrative pseudocode rather than executable SQL. The application's database driver should identify the relevant error codes and handle transaction cleanup correctly.
17.3 Avoid Duplicate External Side Effects
A transaction retry may execute application logic more than once. Avoid sending the same payment request, email, or external notification repeatedly just because the database transaction was retried. Use idempotency keys, an outbox pattern, or another suitable design for external side effects.
18. Best Practices for High-Concurrency MySQL Applications
- Use InnoDB: Prefer a transactional storage engine for data that requires reliable concurrent updates.
- Keep transactions short: Complete database work promptly and avoid long periods between locking operations and transaction completion.
- Use consistent lock ordering: Access shared records and tables in a predictable order across application code paths.
- Create appropriate indexes: Support common filters, joins, and locking queries with suitable indexes.
- Use precise WHERE conditions: Limit modifications to the records that actually need to change.
- Prefer atomic SQL operations: Use conditional updates for simple inventory and counter operations when suitable.
- Lock only when necessary: Avoid locking reads for queries that do not require them.
- Handle deadlocks automatically: Implement safe, bounded retries for retryable transactions.
- Monitor transaction activity: Investigate long-running transactions and recurring lock waits.
- Review isolation levels: Select the isolation level that matches the application's correctness requirements.
- Test with concurrency: Simulate simultaneous users and conflicting updates before deployment.
- Keep external work outside transactions when possible: Avoid holding database locks while waiting for external services.
- Validate before committing: Check business rules and affected-row counts for important changes.
- Record diagnostic details: Log relevant transaction IDs, SQL operation context, and error codes without exposing sensitive information.
19. Common Locking and Deadlock Problems
| Problem |
Possible Cause |
Recommended Solution |
| UPDATE waits for a long time. |
Another transaction holds a conflicting lock. |
Identify the blocking transaction and reduce unnecessary transaction duration. |
| Deadlock error occurs. |
Transactions acquired locks in conflicting orders. |
Use consistent access ordering and retry the complete transaction safely. |
| Unexpectedly many rows are locked. |
A query examines a large range or lacks a suitable index. |
Review the query plan, indexes, isolation level, and locking requirements. |
| Application requests time out. |
Lock waits, long transactions, or other resource pressure. |
Inspect lock-wait diagnostics and improve transaction design. |
| Inventory becomes incorrect. |
Application-level read-modify-write logic is not safely coordinated. |
Use atomic conditional updates or an appropriate locking transaction. |
| Transaction locks remain active. |
The application did not commit or roll back promptly. |
Ensure every transaction path handles success and failure correctly. |
| Deadlocks recur frequently. |
High contention, inconsistent ordering, range locks, or inefficient queries. |
Inspect deadlock reports and redesign the affected operations. |
20. Practical Exercises
Exercise 1: Understand Exclusive Locks
Create a table with an InnoDB storage engine. Open two sessions, lock the same record with SELECT FOR UPDATE in the first session, and try to update it in the second session. Observe how the second operation waits.
Exercise 2: Test Shared Locks
Use SELECT FOR SHARE in two sessions and observe how compatible shared locks behave. Then attempt an update and observe the effect of the existing locks.
Exercise 3: Create a Deadlock
Use two sessions to update two records in opposite orders. Observe the deadlock error and examine the latest deadlock details using SHOW ENGINE INNODB STATUS.
Exercise 4: Investigate Lock Waits
Keep one transaction open while another waits for a conflicting lock. Inspect active transactions and Performance Schema lock-wait information.
Exercise 5: Compare Index Performance
Run an UPDATE that filters on a non-indexed column, inspect its execution plan, add an appropriate index if justified, and compare the results.
Exercise 6: Implement Safe Inventory Updates
Create a products table and implement a conditional decrement that succeeds only when stock is available. Verify the affected-row count and test simultaneous purchase attempts.
21. Mini Project: Inventory Management with Concurrent Transactions
Project Objective: Develop a small inventory workflow that safely handles multiple customers attempting to purchase the same product.
Project Requirements
- Create an InnoDB products table.
- Insert sample product records.
- Implement a conditional stock decrement.
- Verify whether the update affected one row.
- Commit successful stock reservations.
- Handle insufficient stock without committing an invalid reservation.
- Simulate two sessions purchasing the same product.
- Inspect lock waits and deadlock errors where applicable.
Sample SQL
CREATE TABLE IF NOT EXISTS inventory_products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
stock_quantity INT NOT NULL
) ENGINE = InnoDB;
INSERT INTO inventory_products
VALUES (1, 'Wireless Mouse', 10)
ON DUPLICATE KEY UPDATE
product_name = VALUES(product_name);
START TRANSACTION;
UPDATE inventory_products
SET stock_quantity = stock_quantity - 1
WHERE product_id = 1
AND stock_quantity > 0;
-- Application code checks the affected-row count.
-- If one row was updated, the reservation succeeded.
-- If zero rows were updated, roll back or handle
-- the unavailable-stock result as appropriate.
COMMIT;
SELECT * FROM inventory_products;
This SQL illustrates the database operation. In a production application, the client must inspect the affected-row count before deciding to commit. If the update fails to reserve stock, the application should handle that result without treating it as a successful purchase.
Expected Learning Outcomes
- Understand how concurrent requests interact with the same record.
- Use atomic SQL updates to protect inventory quantities.
- Observe the role of InnoDB locks in concurrent operations.
- Understand how transaction boundaries affect consistency.
- Identify and investigate blocking and deadlocks.
22. Interview Questions and Answers
Q1. What is a database lock?
A database lock is a mechanism that coordinates access to a resource so that concurrent transactions do not perform conflicting operations unsafely.
Q2. What is concurrent database access?
It occurs when multiple transactions access or modify database data during overlapping periods.
Q3. What is the difference between shared and exclusive locks?
Shared locks allow compatible locking reads, while exclusive locks protect records for conflicting modifications and are incompatible with other locks that conflict with them.
Q4. What is a deadlock?
A deadlock occurs when transactions wait for resources held by one another in a circular dependency.
Q5. How does InnoDB handle deadlocks?
InnoDB detects deadlocks and normally rolls back one transaction so that the remaining transaction can proceed.
Q6. What is a lock-wait timeout?
It occurs when a transaction waits for a lock longer than the configured timeout. It does not necessarily indicate a deadlock.
Q7. What is SELECT FOR UPDATE?
It is a locking read that requests exclusive locks on the applicable records, allowing a transaction to read data it intends to modify safely.
Q8. What is SELECT FOR SHARE?
It is a locking read that requests shared locks on applicable records.
Q9. What is MVCC?
Multi-Version Concurrency Control allows certain reads to access consistent versions of data without always blocking on concurrent modifications.
Q10. What is a record lock?
A record lock protects an index record from conflicting operations.
Q11. What is a gap lock?
A gap lock protects a gap between index records and can prevent inserts into that gap under applicable conditions.
Q12. What is a next-key lock?
A next-key lock combines a record lock with a lock on the gap preceding the record.
Q13. How can deadlocks be reduced?
Use consistent lock ordering, keep transactions short, create appropriate indexes, and avoid unnecessary locking.
Q14. How do you inspect deadlock details?
SHOW ENGINE INNODB STATUS;
Review the latest detected deadlock section when it is available.
Q15. How do you inspect InnoDB lock waits?
Use Performance Schema tables such as data_locks and data_lock_waits, along with active transaction information.
Q16. Can deadlocks be eliminated completely?
Not always. Even well-designed systems can experience deadlocks under certain concurrent workloads. Applications should minimize their frequency and handle them safely.
Q17. Why are indexes important for locking?
Indexes can help MySQL locate matching records efficiently and reduce unnecessary scanning, which can improve performance and reduce some forms of lock contention.
Q18. What is a lost update?
A lost update occurs when concurrent changes overwrite one another in a way that causes an intended modification to disappear.
Q19. Why should transactions be short?
Short transactions reduce lock duration, lower contention, and decrease the chance of blocking other transactions.
Q20. What should an application do after a deadlock?
It should treat the affected transaction as failed and, when safe, retry the complete logical transaction with bounded retries and appropriate error handling.
23. Quick Revision Checklist
- Concurrent access means multiple transactions operate during overlapping periods.
- Locks coordinate conflicting database operations.
- Shared locks are used for locking reads that request shared access.
- Exclusive locks protect records involved in conflicting modifications.
- InnoDB supports row-level locking, MVCC, and transactional operations.
- Record, gap, and next-key locks have different purposes.
- A deadlock is a circular waiting condition involving transactions.
- InnoDB normally detects deadlocks and rolls back a victim transaction.
- A lock-wait timeout is not necessarily a deadlock.
- SELECT FOR UPDATE requests exclusive locks on applicable records.
- SELECT FOR SHARE requests shared locks on applicable records.
- SHOW ENGINE INNODB STATUS helps diagnose deadlocks.
- Performance Schema can provide lock and lock-wait information.
- Consistent lock ordering and short transactions help reduce deadlocks.
- Appropriate indexes can improve query performance and reduce unnecessary scanning.
- Applications should safely handle deadlocks and retry transactions when appropriate.
24. Conclusion
Locks, deadlocks, and concurrent database access are essential concepts for developing reliable MySQL applications. Locks coordinate access to shared data, while concurrency control allows multiple transactions to work efficiently without compromising the database's consistency rules. InnoDB combines locking and MVCC to support concurrent operations.
Deadlocks can occur when transactions acquire resources in conflicting orders. Developers can reduce their frequency by using consistent locking sequences, suitable indexes, precise queries, and short transactions. They should also monitor lock waits, inspect deadlock reports, and implement safe retry logic for failed transactions.
By understanding these techniques, developers can build database applications that handle concurrent users more reliably and maintain data integrity under demanding workloads.
Explore the Course: Learn SQL, database management, and practical MySQL concepts through the JustAcademy MySQL Training Course.
Register for a Demo: Visit JustAcademy Course Demo Registration to learn more about the training.