AJAX - AJAX Optimistic Concurrency Control

Introduction

AJAX Optimistic Concurrency Control is a technique used to prevent data conflicts when multiple users or application processes attempt to update the same data at nearly the same time. It is particularly useful in web applications where information can be edited dynamically without refreshing the entire page.

The main idea behind optimistic concurrency control is that the application assumes conflicts will be relatively uncommon. Instead of locking a record whenever someone starts editing it, the application allows users to work normally and checks for conflicts when they attempt to save their changes.

For example, suppose two employees open the same customer record at the same time. Employee A changes the customer's phone number, while Employee B changes the customer's address. If both users save their versions without checking whether the data has changed, one update could overwrite the other. Optimistic concurrency control helps detect such situations before an unintended update occurs.

Why Concurrency Control Is Needed

Consider a database containing the following customer information:

Customer ID: 101
Name: Rahul
Phone: 9876543210
City: Mysore

Two users, User A and User B, retrieve this record through AJAX.

At this point, both users have the same version of the data.

User A changes the city:

City: Bengaluru

User B changes the phone number:

Phone: 9123456789

If User A saves first, the database becomes:

Phone: 9876543210
City: Bengaluru

User B is still working with the old version of the record. If User B now sends the entire old record along with the changed phone number, the server might replace the database record with:

Phone: 9123456789
City: Mysore

User A's city change has now been lost.

This situation is known as a lost update.

Optimistic concurrency control is designed to identify this kind of conflict.

How Optimistic Concurrency Control Works

A common approach is to give every database record a version number.

For example:

Customer ID: 101
Name: Rahul
Phone: 9876543210
City: Mysore
Version: 5

When an AJAX request retrieves this record, the client also receives its current version.

For example:

{
    "id": 101,
    "name": "Rahul",
    "phone": "9876543210",
    "city": "Mysore",
    "version": 5
}

The user modifies the information and submits it later.

The AJAX request sends the version number along with the updated information:

{
    "id": 101,
    "phone": "9123456789",
    "city": "Mysore",
    "version": 5
}

The server checks whether the database record is still at version 5.

If it is still version 5, the update can safely proceed.

The server then updates the record and changes the version to 6.

Version: 6

What Happens When a Conflict Occurs

Now consider that another user has already modified the same record.

The database may now contain:

Customer ID: 101
Phone: 9876543210
City: Bengaluru
Version: 6

The second user's AJAX request still contains:

Version: 5

The server compares:

Client Version: 5
Database Version: 6

Because the versions are different, the server knows that somebody else has modified the record since the second user originally retrieved it.

Instead of blindly overwriting the newer information, the server can reject the update.

A response might look like:

{
    "success": false,
    "error": "CONFLICT",
    "message": "The record has been modified by another user.",
    "currentVersion": 6
}

The client-side AJAX code can then inform the user that the information has changed.

Example Using AJAX

A basic AJAX request might use the Fetch API:

fetch("/api/customer/101", {
    method: "PUT",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        phone: "9123456789",
        city: "Mysore",
        version: 5
    })
})
.then(response => response.json())
.then(data => {
    if (data.success) {
        console.log("Update successful");
    } else if (data.error === "CONFLICT") {
        console.log("The record was modified by another user");
    }
});

The important part is that the client sends the version it originally received.

The server does not simply accept the update. It first verifies whether that version is still current.

Server-Side Verification

The server might conceptually perform an operation similar to:

UPDATE customers
SET phone = '9123456789',
    city = 'Mysore',
    version = version + 1
WHERE id = 101
AND version = 5;

If one row is updated, the operation was successful.

If zero rows are updated, it can indicate that the record's version has already changed.

This provides a simple way of detecting concurrent modifications.

Using Timestamps

Version numbers are not the only mechanism available.

Applications can also use a timestamp.

For example:

id: 101
city: Mysore
updatedAt: 2026-09-20 10:15:30

When the client retrieves the record, it stores the updatedAt value.

When the user submits an update, the client sends the timestamp it originally received.

The server compares the supplied timestamp with the current database timestamp.

If they are different, another update has occurred and the server can reject the request.

However, version numbers are often easier to manage because they provide a simple sequential representation of the record's revision.

Using ETags

Another HTTP-based approach is the use of ETags.

An ETag is a value that represents a particular version of a resource.

For example, the server may return:

ETag: "customer-101-v5"

The client can later send:

If-Match: "customer-101-v5"

The server checks whether the resource still has the same ETag.

If it does, the update can proceed.

If the ETag has changed, the server can return a conflict response rather than overwriting the newer version.

This approach is particularly useful for web APIs because it integrates concurrency checking with HTTP request handling.

Handling Conflicts on the Client Side

Detecting a conflict is only one part of the process. The AJAX application should also decide what to do when a conflict occurs.

A common approach is to display a message such as:

This information was changed by another user.
Please review the latest version before saving your changes.

The application may then retrieve the latest version from the server.

For example:

fetch("/api/customer/101")
    .then(response => response.json())
    .then(customer => {
        console.log(customer);
    });

The user can compare the latest data with their changes and decide which information should be retained.

Automatic Conflict Resolution

Some applications can resolve certain conflicts automatically.

Suppose User A changes the city and User B changes the phone number. If the application knows that these are independent fields, it may be possible to combine both changes.

The resulting record could contain:

Phone: 9123456789
City: Bengaluru

However, automatic merging should be used carefully. Some changes may depend on one another, and blindly merging data can produce incorrect results.

Difference Between Optimistic and Pessimistic Concurrency

Optimistic concurrency control assumes that conflicts are uncommon.

The application allows multiple users to access and edit data and checks for conflicts when changes are submitted.

Pessimistic concurrency control takes the opposite approach. It attempts to prevent simultaneous modifications by locking the resource while one user is working with it.

For example, a pessimistic system might lock a customer record while User A is editing it. User B would have to wait until User A finishes.

Optimistic concurrency is often more suitable for modern web applications because keeping a database record locked while a user spends several minutes editing a form can reduce system flexibility and scalability.

Advantages

Optimistic concurrency control has several advantages.

First, it avoids unnecessary database locks. Multiple users can read and work with the same information without blocking one another.

Second, it works well with AJAX-based applications because updates can be performed asynchronously without requiring a complete page reload.

Third, it can improve scalability because the server does not need to maintain long-running locks for users who are editing information.

Fourth, it protects against accidental overwriting of newer data by detecting that a record has changed since it was retrieved.

Limitations

Optimistic concurrency control does not completely eliminate conflicts. It detects them rather than preventing users from making simultaneous changes.

The application also needs a clear strategy for handling conflicts. Simply displaying an error message may not provide a good user experience for complex applications.

Another limitation is that the server must correctly implement version checking. If the server accepts an update without validating the supplied version, the concurrency protection can be bypassed.

Practical AJAX Workflow

A typical AJAX application using optimistic concurrency control follows this sequence:

1. Client requests data from the server
2. Server returns the data and its version
3. Client displays the data
4. User modifies the data
5. Client sends the changes and original version
6. Server compares the supplied version with the database version
7. If versions match, the update is performed
8. If versions differ, the update is rejected
9. Client informs the user about the conflict
10. Latest data can be retrieved for review

Conclusion

AJAX Optimistic Concurrency Control provides a reliable way to manage simultaneous data modifications in web applications. Instead of locking records while users are editing them, the system allows normal editing and verifies the record's version when an update is submitted.

Version numbers, timestamps, and HTTP ETags can all be used to identify whether data has changed. When the server detects that another user has already modified the record, it can reject the outdated update and allow the application to handle the conflict appropriately.

This approach is especially useful for AJAX applications where multiple users can view and modify the same server-side information without continuously refreshing the webpage.