Concurrency occurs when multiple requests try to access or modify the same shared resource at the same time.
- Seat status = FREE
- User1, User2, User3 read simultaneously → all see FREE
- All update → BOOKED
Result: Same seat booked multiple times ❌
- Race Condition: Multiple operations compete → incorrect result
- Critical Section: Code that accesses shared resource
Example: if (seat.status == FREE) { seat.status = BOOKED; }
- Single JVM (multi-threading)
- Distributed systems (multiple servers)
Example:
- User1 → Server A
- User2 → Server B
Each server has its own lock → no coordination ❌
Conclusion: Need Distributed Concurrency Control
Maintain database consistency
Atomicity → All or nothing
- A = 100, B = 50
- Deduct 20 from A → 80
- Add 20 to B → 70
Without transaction:
- If credit fails → A=80, B=50 ❌
With transaction:
- Failure → rollback → A=100, B=50 ✅
- Multiple reads allowed
- No writes allowed
- Only one writer allowed
- No reads or writes allowed
| Lock Type | Read Allowed | Write Allowed |
|---|---|---|
| Shared | Yes | No |
| Exclusive | No | No |
Dirty Read:
- Reading uncommitted data
Non-Repeatable Read:
- Same row → different values
Phantom Read:
- Same query → different number of rows
| Level | Dirty Read | Non-Repeatable | Phantom |
|---|---|---|---|
| Read Uncommitted | Allowed | Allowed | Allowed |
| Read Committed | Prevented | Allowed | Allowed |
| Repeatable Read | Prevented | Prevented | Allowed |
| Serializable | Prevented | Prevented | Prevented |
Read Uncommitted:
- No locks
Read Committed:
- Read → short shared lock (released immediately)
- Write → exclusive lock till commit
Repeatable Read:
- Read → shared lock till end of transaction
- Write → exclusive lock till end
Serializable:
- Same as repeatable read + range locks
Higher isolation = More consistency
Higher isolation = Less concurrency
Assume conflicts are rare
Use versioning
-
Read row (version = v1)
-
Perform logic
-
Update with condition: UPDATE table SET value = ?, version = version + 1 WHERE id = ? AND version = v1;
-
If rows updated = 0 → conflict → retry
- High performance
- No locks
- No deadlocks
- Retry overhead
- Low contention systems
Assume conflicts WILL happen
Lock resource before modifying
Example: SELECT * FROM seat WHERE id = 1 FOR UPDATE;
- Safe
- Prevents conflicts upfront
- Slower
- Deadlocks possible
- High contention systems
- T1 locks A → wants B
- T2 locks B → wants A
Both wait forever ❌
- Timeout
- Abort one transaction
- Retry
| Feature | Optimistic | Pessimistic |
|---|---|---|
| Approach | Versioning | Locking |
| Concurrency | High | Low |
| Deadlock | No | Possible |
| Performance | Fast | Slower |
| Conflict Handling | Retry | Prevent upfront |
Multiple servers → local locks don’t work
- DB constraints (unique keys)
- Redis locks (SETNX)
- Queue-based serialization
Step 1: “This is a race condition on a shared resource.”
Step 2: “Seat booking is the critical section.”
Step 3: Solutions
Optimistic:
- Use versioning + retry
Pessimistic:
- Use DB locks (SELECT FOR UPDATE)
Distributed:
- Redis lock / DB constraint
- Concurrency = Shared resource problem
- Transactions ensure consistency
- Locks control access
- Isolation controls visibility
- Optimistic = Retry-based
- Pessimistic = Lock-based
- Shared = Read
- Exclusive = Write
- Optimistic = Check & Retry
- Pessimistic = Lock & Wait
- Serializable = No anomalies allowed