ADO - Optimistic and Pessimistic Concurrency Control in ADO.NET
Concurrency control is a technique used in database applications to ensure that multiple users can access and modify data without causing inconsistencies or data corruption. In multi-user environments, it is common for several users to access the same database records simultaneously. Without proper concurrency control, updates made by one user may overwrite the changes made by another, resulting in incorrect or lost information.
ADO.NET provides mechanisms to handle concurrent access to data effectively. The two primary approaches are Optimistic Concurrency Control and Pessimistic Concurrency Control. Each method has its own advantages, disadvantages, and suitable use cases.
What is Concurrency?
Concurrency refers to the situation where multiple users or applications access the same database data at the same time. Consider an online shopping application where two administrators attempt to update the price of the same product simultaneously. If there is no concurrency control, one administrator's changes may overwrite the other's without warning.
Proper concurrency management ensures that:
-
Data remains accurate.
-
Simultaneous updates do not create conflicts.
-
Users receive the latest information.
-
Database integrity is maintained.
Why is Concurrency Control Important?
Without concurrency control, database applications may experience several problems.
Lost Updates
A user modifies a record, but before saving it, another user changes the same record and saves it. When the first user saves later, the second user's changes are lost.
Dirty Reads
A transaction reads data that has been modified but not yet committed by another transaction. If that transaction is rolled back, the first transaction has read invalid data.
Non-Repeatable Reads
A record is read twice during the same transaction, but another transaction modifies it between the two reads, resulting in different values.
Phantom Reads
A query returns different sets of rows because another transaction inserts or deletes records while the query is executing.
Concurrency control minimizes these issues by coordinating database access.
Optimistic Concurrency Control
Optimistic concurrency assumes that conflicts between users are rare. Therefore, records are not locked while users are editing them.
Instead, ADO.NET checks whether another user has modified the record before saving the changes.
If a conflict is detected, the update fails, and the application informs the user.
How Optimistic Concurrency Works
-
User A retrieves a record.
-
User B retrieves the same record.
-
User A modifies and saves the record.
-
User B modifies the same record.
-
Before saving, ADO.NET compares the original values with the current database values.
-
Since the record has already changed, User B's update is rejected.
-
User B must reload the latest data before making changes again.
Example
Assume a table named Employees.
| EmployeeID | Name | Salary |
|---|---|---|
| 101 | Ravi | 50000 |
User A opens the record.
Salary = 50000
User B also opens the same record.
Salary = 50000
User A updates the salary.
Salary = 55000
The database now contains:
| EmployeeID | Name | Salary |
|---|---|---|
| 101 | Ravi | 55000 |
User B tries to update the salary to 53000.
ADO.NET checks the original value.
Original Salary = 50000
Database Salary = 55000
Since they are different, the update is rejected.
The application can display a message such as:
"The record has been modified by another user. Please refresh the data."
Implementing Optimistic Concurrency
The UPDATE statement includes the original values in its WHERE clause.
UPDATE Employees
SET Salary = @NewSalary
WHERE EmployeeID = @EmployeeID
AND Salary = @OriginalSalary
If another user has already modified the salary, the WHERE condition fails.
No rows are updated.
The application detects this by checking the number of affected rows.
int rowsAffected = command.ExecuteNonQuery();
if(rowsAffected == 0)
{
Console.WriteLine("Concurrency conflict detected.");
}
Advantages of Optimistic Concurrency
Better Performance
No database locks are held while users edit data.
Higher Scalability
Many users can access the same records simultaneously.
Less Resource Consumption
Database resources are not occupied by long-running locks.
Suitable for Web Applications
Users may keep pages open for several minutes before submitting data.
Keeping records locked during that time would reduce performance.
Disadvantages of Optimistic Concurrency
Update Failures
Users may have to re-enter changes if another user updates the record first.
Conflict Resolution Required
Applications must provide a mechanism for resolving conflicts.
Not Suitable for Highly Competitive Data
Frequent updates increase the chances of conflicts.
Pessimistic Concurrency Control
Pessimistic concurrency assumes that conflicts are likely to occur.
Therefore, when one user begins editing a record, the database immediately locks it.
Other users cannot modify the record until the first user completes the transaction.
How Pessimistic Concurrency Works
-
User A retrieves a record.
-
Database locks the record.
-
User B attempts to edit the same record.
-
User B must wait until User A finishes.
-
User A saves changes.
-
Lock is released.
-
User B can now edit the record.
Example
Employee record:
| EmployeeID | Name | Salary |
|---|---|---|
| 101 | Ravi | 50000 |
User A starts editing.
The database locks the record.
User B attempts to edit.
Database returns:
"Record is currently locked."
User A finishes editing.
Salary becomes 55000.
The lock is removed.
User B can now edit the updated record.
Using Transactions for Pessimistic Concurrency
Locks are generally maintained within transactions.
SqlTransaction transaction = connection.BeginTransaction();
SqlCommand command = new SqlCommand(sql, connection, transaction);
command.ExecuteNonQuery();
transaction.Commit();
If an error occurs,
transaction.Rollback();
This ensures data consistency.
Advantages of Pessimistic Concurrency
Prevents Conflicts
Only one user can modify a record at a time.
High Data Integrity
No accidental overwriting of data occurs.
Suitable for Critical Systems
Ideal for banking, inventory management, reservation systems, and financial applications.
Disadvantages of Pessimistic Concurrency
Reduced Performance
Locks prevent other users from accessing the same records.
Longer Waiting Time
Users may experience delays while waiting for locks to be released.
Deadlocks
Two transactions may wait indefinitely for each other to release resources.
Example:
Transaction A locks Table X.
Transaction B locks Table Y.
Transaction A waits for Table Y.
Transaction B waits for Table X.
Neither transaction can proceed.
Comparing Optimistic and Pessimistic Concurrency
| Feature | Optimistic Concurrency | Pessimistic Concurrency |
|---|---|---|
| Record Locking | No | Yes |
| Performance | High | Lower |
| Conflict Detection | During update | Before update |
| Database Locks | Rare | Frequent |
| Scalability | Excellent | Limited |
| Suitable for Web Applications | Yes | Usually No |
| Suitable for Banking Systems | Less Suitable | Highly Suitable |
| User Waiting Time | Minimal | Higher |
| Resource Usage | Low | High |
| Conflict Resolution | Required | Rarely Needed |
When to Use Optimistic Concurrency
Optimistic concurrency is recommended when:
-
Most users only read data.
-
Record updates are infrequent.
-
High application performance is important.
-
Web applications have many concurrent users.
-
Users may keep records open for extended periods before saving.
Examples include:
-
Student information systems
-
Online learning platforms
-
Employee management systems
-
Customer relationship management applications
-
E-commerce product catalogs
When to Use Pessimistic Concurrency
Pessimistic concurrency is appropriate when:
-
Data is frequently modified.
-
Data accuracy is critical.
-
Simultaneous updates must be prevented.
-
Financial transactions are involved.
-
Data conflicts could have serious consequences.
Examples include:
-
Banking applications
-
Airline reservation systems
-
Railway ticket booking systems
-
Hospital patient record systems
-
Stock trading platforms
Best Practices
-
Use optimistic concurrency as the default strategy for most ADO.NET applications because it provides better scalability and performance.
-
Use pessimistic concurrency only when the risk and cost of conflicting updates are high.
-
Keep transactions as short as possible to reduce lock duration and improve throughput.
-
Check the number of rows affected after executing an UPDATE or DELETE statement to detect optimistic concurrency conflicts.
-
Handle concurrency exceptions gracefully by informing users of conflicts and allowing them to refresh and retry.
-
Design SQL queries and indexes efficiently so that updates complete quickly, reducing the likelihood of contention.
-
Regularly test applications under multi-user conditions to identify concurrency issues before deployment.
Summary
Concurrency control is essential for maintaining data consistency in applications where multiple users access the same database. ADO.NET supports two primary approaches: optimistic concurrency, which allows simultaneous access and checks for conflicts during updates, and pessimistic concurrency, which prevents conflicts by locking records during editing. Optimistic concurrency offers better performance and scalability and is widely used in web and enterprise applications, while pessimistic concurrency provides stronger protection against conflicting updates and is preferred for systems where data accuracy is critical, such as banking, reservation, and financial applications. Selecting the appropriate strategy depends on the application's performance requirements, expected user activity, and the importance of maintaining data integrity.