← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Optimistic Locking

database Advanced

Also Known As

optimistic concurrency control version column pattern compare and swap database

TL;DR

A concurrency pattern using a version column to detect conflicting concurrent writes — no row locks held between read and write.

Explanation

A version INT (or updated_at DATETIME) column is incremented on every UPDATE. The WHERE clause includes AND version = :expected — if rowCount() returns 0, another process changed the row first. Advantages: no lock contention, scales well for read-heavy workloads. Disadvantages: requires retry logic, degrades under high write contention on the same row. Preferred over pessimistic locking for most web application patterns.

Common Misconception

Optimistic locking is always better than pessimistic locking. Under high write contention on the same row, optimistic locking causes excessive retries — pessimistic locking is more predictable in that case.

Why It Matters

Pessimistic locking holds locks during the full read-think-write cycle causing timeouts. Optimistic locking eliminates contention — conflicting writes are detected at commit time, not locked upfront.

Common Mistakes

  • Not implementing retry logic — silently discarding the failed update.
  • Using updated_at as the version — two updates within the same second both pass the check.
  • Using optimistic locking for financial operations where a lost update is unacceptable.

Avoid When

  • Avoid when conflict rate is high — retries become the dominant code path.
  • Do not use for financial transfers where a missed update is a data integrity failure.

When To Use

  • Use for read-heavy workflows where conflicts are infrequent.
  • Use when holding locks between read and write is impractical — e.g. user edits a form for 30 seconds.

Code Examples

✗ Vulnerable
// Last write wins — concurrent change silently overwritten
$pdo->prepare('UPDATE products SET name = ? WHERE id = ?')->execute([$newName, $id]);
✓ Fixed
$stmt = $pdo->prepare('SELECT id, name, version FROM products WHERE id = ?');
$stmt->execute([$id]);
$product = $stmt->fetch();

$stmt = $pdo->prepare(
    'UPDATE products SET name = ?, version = version + 1 WHERE id = ? AND version = ?'
);
$stmt->execute([$newName, $id, $product['version']]);
if ($stmt->rowCount() === 0) {
    throw new ConcurrentModificationException('Row was modified by another process — retry');
}

Added 31 Mar 2026
Views 34
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 1 ping S 1 ping M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Perplexity 6 ChatGPT 6 Google 4 Unknown AI 2 Ahrefs 1
crawler 17 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
⚙ Fix effort: Medium
⚡ Quick Fix
Add a version INT NOT NULL DEFAULT 0 column, increment in every UPDATE, check rowCount() === 1 after execute()
📦 Applies To
web cli
🔗 Prerequisites
🔍 Detection Hints
UPDATE without version check on shared mutable rows
Auto-detectable: ✗ No
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File Tests: Update

✓ schema.org compliant