Two users. One record. Two different updates. And a tiny race condition that can silently destroy your data.

Imagine you're booking the last available appointment with a popular specialist. 🏥

You select 10:00 AM. Another person selects the same slot at almost exactly the same moment.

Both screens show availability. Both users click Confirm.

Now the uncomfortable question: Who gets the appointment?

If your system doesn't handle concurrent updates correctly, both users might receive a confirmation for the same slot.

The problem isn't that either user did something wrong. It's that your application allowed two operations to make decisions using the same outdated information.

This is where database locking becomes essential.

There are two common approaches to consider: optimistic locking and pessimistic locking.

Let's understand when each one makes sense. 👇

🟢 1. Optimistic Locking: Assume Conflicts Are Uncommon#

Optimistic locking follows a simple idea:

Let operations proceed, but verify that nobody changed the data before saving your update.

Imagine you're editing a travel itinerary. You open a trip, make several changes, and spend five minutes adjusting the schedule.

Meanwhile, another user updates the same itinerary and saves their changes.

When you finally click Save, should your version silently overwrite theirs?

Absolutely not.

With optimistic locking, the system checks whether the record has changed since you originally read it. If it has, your update is rejected or flagged as a conflict, allowing you to reload, compare, or merge the changes.

🔍 How it works:

  1. Read the record and its current version.

  2. Make your changes without holding a database lock throughout the editing process.

  3. Check the version when saving.

  4. Accept the update if the version is unchanged; otherwise, report the conflict.

For example, a record might have version 12 when you open it. Another user saves a change, advancing it to version 13.

Your save still expects version 12.

The mismatch tells the system that your information is outdated.

✅ When is optimistic locking useful?#

  • 📝 Collaborative editing and content management.

  • 👤 Updating user profiles and settings.

  • 📦 Administrative interfaces where simultaneous edits are relatively uncommon.

  • 🔄 Workflows where conflicts can be reviewed or resolved.

The biggest advantage? You avoid holding database locks while someone spends minutes editing a form.

The trade-off? A conflicting update may need to be retried or reconciled. If conflicts happen constantly, users can become frustrated.

🔴 2. Pessimistic Locking: Secure the Record Before Changing It#

Now imagine a warehouse with exactly one unit of a high-demand product left.

Two checkout processes attempt to reserve it simultaneously.

Waiting until both processes finish calculating their updates could be dangerous. The system needs to coordinate access to the inventory before either process commits a reservation.

Pessimistic locking takes a different approach:

Acquire a lock before performing the critical operation, so competing transactions must wait or fail while the lock is held.

🔍 How it works:

  1. Start a database transaction.

  2. Acquire a lock on the relevant record.

  3. Read the current data and perform the operation.

  4. Commit the transaction and release the lock.

The second transaction cannot acquire the same conflicting lock immediately. Depending on the database and lock configuration, it waits or receives an error.

Once the first transaction finishes, the next operation can proceed using the updated state.

✅ When is pessimistic locking useful?#

  • 🎟️ Reserving scarce tickets or appointment slots.

  • 📦 Allocating limited inventory.

  • 💰 Performing financial operations that require carefully coordinated updates.

  • ⚙️ Critical workflows where competing operations must be serialized.

The biggest advantage? It coordinates competing operations before they can independently modify the same locked record.

The trade-off? Locks consume time and resources. Transactions held open too long can cause contention, delays, or deadlocks.

A lock is protection—not a reason to keep a transaction open while performing slow network requests or waiting for user input.

⚖️ 3. The Real Difference#

Here's the simplest way to compare them.

Consideration

🟢 Optimistic

🔴 Pessimistic

Basic strategy

Detect conflicts when saving

Lock before modifying

Concurrent access

Usually proceeds without holding a write lock during the work

Conflicting operations may wait

Best suited for

Infrequent conflicts

Operations needing immediate coordination

Main challenge

Handling rejected updates

Managing contention and deadlocks

Typical example

Editing an itinerary

Reserving the last appointment

One important detail: optimistic locking still relies on atomic checks or equivalent database guarantees. Pessimistic locking also depends on transactions and correct locking behavior.

Neither approach automatically solves every concurrency problem.

For example, locking one inventory row doesn't necessarily protect a business rule involving several different rows unless the transaction and locking strategy cover the relevant data.

🧠 4. So, Which One Should You Choose?#

Don't choose based on which technique sounds safer or faster.

Start with the problem your application actually has.

Choose optimistic locking when:

  • Conflicts are relatively rare.

  • Users may work on the same record independently.

  • Rejecting or reconciling a conflicting update is acceptable.

Choose pessimistic locking when:

  • Concurrent operations must be carefully coordinated.

  • Conflicts are frequent enough to make repeated retries expensive.

  • A critical operation needs exclusive access to specific data while it executes.

And remember: pessimistic locking isn't automatically the better choice for payments, just as optimistic locking isn't automatically the better choice for every form.

The right decision depends on the consistency guarantees you need, the cost of a conflict, and how your database transactions are designed.

Sometimes, a conditional atomic update or a unique constraint is a better solution than either locking strategy alone.

🚀 The Takeaway#

Concurrency problems are tricky because each request can appear correct when viewed in isolation.

The trouble begins when multiple requests interact with the same data.

Optimistic locking says, "Go ahead, but make sure the data hasn't changed since you read it."

Pessimistic locking says, "Secure access first, then perform the critical operation."

Both approaches protect data integrity in different ways.

The real engineering skill isn't memorizing the definitions. It's understanding how your system behaves when two operations want to change the same thing at the same time.

✍️ Notes from beneath the surface — Exploring the decisions and hidden complexities behind the software we build.