Let’s Talk About Optimistic Concurrency Control
Concurrency is one of those things that always sounds straightforward when you're reading theory. But the moment you start building real-world systems with actual users, it gets messy real quick. Especially when two users try to update the same resource at the same time. So, how do we handle that elegantly? Enter Optimistic Locking — a technique that I’ve seen misunderstood and misused way too often.
The Optimism in Locking
The name itself gives it away — optimistic concurrency control is based on the idea that conflicts are rare. Instead of stopping other users from touching the resource while one user is working on it, we just… let everyone go ahead. Everyone can read and try to update. The system will then handle things if there's a conflict after the fact.
And guess what? In most cases, this actually works well. Until it doesn’t.
Let’s take a look at how this works — the version number approach is what I usually prefer over timestamps (those server clocks can be sketchy — I don't trust them, and neither should you).
The Steps:
- We add a column in the DB table — let’s call it
version
. - When a user fetches a row, we also fetch the current version.
- They update the data and bump the version by one.
- While writing back, we check if the version in the DB is still what we fetched earlier.
- If yes, cool, go ahead and update.
- If not, someone else beat you to it — go back, retry.
Sounds easy enough, right?
But It’s Not All Rainbows
Let me tell you where this optimism starts falling apart — when things get really concurrent.
Imagine a hotel booking system. A popular property has one room left. Ten users jump in at the same time — all read the same row, with version 1
.
Each tries to book. All ten attempt to update the count and bump version to 2
.
But only one wins. Nine others get slapped with version mismatch errors and are forced to retry. And they’ll keep retrying until one of them wins the next round. Meanwhile, user experience goes down the drain. It’s accurate, sure, but it feels broken.
So yes, optimistic locking is not a silver bullet — it's fast, but only when contention is low.
And What About Pessimistic Locking?
That’s the other side of the coin. Pessimistic locking takes the “better safe than sorry” approach. It says: “Hey, you wanna modify this row? Cool, but I’m locking it for you until you’re done.”
No one else gets to touch it until you're finished. Fewer conflicts, but more blocking. Think of it like standing in line at a vending machine — one at a time, please.
Pessimistic locking can avoid retries and version clashes altogether, but it comes at the cost of throughput and system-wide locks. Which means if you’re scaling, it might not be ideal.
So, What Should You Use?
As always — it depends.
- Low contention? Go with optimistic.
- Heavy write conflicts? Maybe pessimistic is your friend.
But make sure you understand the tradeoffs. Most systems blindly use optimistic locking because it sounds cool. Don’t be that dev.
What's Next
I’ll probably go deeper into pessimistic locking in the next post. There’s quite a bit to unpack there, especially around how it plays out in SQL databases and what you need to watch out for.
Until then, keep it simple, and always understand the why before choosing the how.
Member discussion