← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Deadlock

Concurrency Intermediate
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no', and the code pattern 'lockForUpdate|SELECT.*FOR UPDATE' only identifies potential deadlock-prone code, not actual deadlocks. Deadlocks manifest at runtime under concurrent load — they require runtime testing or production monitoring to catch. No automated static tool can reliably detect them.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions multiple interventions: ensuring consistent lock ordering across transactions, setting lock timeouts, adding retry logic with PDOException handling, and potentially switching to optimistic locking. This typically requires changes across multiple database-touching components to establish consistent ordering and retry patterns.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Deadlock-safe code imposes ongoing discipline: every developer writing concurrent database code must maintain consistent lock ordering conventions and handle retry logic. The applies_to shows this spans web, cli, and queue-worker contexts — anywhere concurrent database access occurs. It's not architectural-level burden but does slow development across multiple work streams.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception explicitly states developers think 'deadlocks only happen in multi-threaded programs' when database deadlocks are extremely common in PHP. This contradicts how developers familiar with single-threaded PHP expect things to work — they don't anticipate concurrency issues in a language without threads, missing that the database layer introduces concurrent access across requests.

About DEBT scoring →

TL;DR

A deadlock occurs when two or more processes each hold a resource the other needs — both wait forever. Prevention requires consistent lock ordering or timeouts.

Explanation

Classic deadlock: Thread A holds Lock 1, wants Lock 2. Thread B holds Lock 2, wants Lock 1. Both wait forever. Four conditions (Coffman): mutual exclusion, hold and wait, no preemption, circular wait. Breaking any one prevents deadlock. Strategies: (1) Lock ordering — always acquire locks in the same order. (2) Timeouts — acquire with timeout, retry. (3) Deadlock detection — detect cycles and break them. (4) Avoid nested locks — flat locking patterns. In PHP/databases: deadlocks occur in MySQL when two transactions update rows in different orders. MySQL auto-detects and kills one transaction — catch PDOException with SQLSTATE 40001.

Common Misconception

Deadlocks only happen in multi-threaded programs — database deadlocks are extremely common in PHP applications with concurrent transactions updating multiple rows.

Why It Matters

Database deadlocks silently fail requests in production unless caught and retried — they're a common source of mysterious 500 errors under load.

Common Mistakes

  • Not retrying on MySQL deadlock error (SQLSTATE 40001).
  • Acquiring database row locks in different orders across transactions.
  • Holding application-level locks while waiting for DB locks.

Code Examples

✗ Vulnerable
// Transaction A: locks user then order
// Transaction B: locks order then user
// → Deadlock
DB::transaction(function() use ($userId, $orderId) {
    User::lockForUpdate()->find($userId);
    Order::lockForUpdate()->find($orderId);
});
✓ Fixed
// Consistent lock order (always user before order):
DB::transaction(function() use ($userId, $orderId) {
    $ids = [$userId, $orderId];
    sort($ids); // Consistent order prevents deadlock
    foreach ($ids as $id) { /* lock in order */ }
});

// Catch and retry deadlocks:
try {
    DB::transaction(fn() => processOrder($orderId));
} catch (\PDOException $e) {
    if ($e->getCode() === '40001') {
        // Deadlock — retry once
        DB::transaction(fn() => processOrder($orderId));
    } else throw $e;
}

Added 23 Mar 2026
Views 112
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping T 1 ping W 3 pings T 1 ping F 0 pings S 0 pings S 0 pings M 1 ping T 2 pings W 0 pings T 2 pings F 0 pings S 1 ping S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 2 pings T 1 ping W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 17 Scrapy 13 Perplexity 11 ChatGPT 7 Google 5 SEMrush 5 Ahrefs 4 Claude 4 Bing 4 Unknown AI 3 PetalBot 3 Meta AI 2 Majestic 1 Sogou 1 Twitter/X 1 Applebot 1 Brave Search 1
crawler 77 crawler_json 5 pre-tracking 1
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Thread concurrency A thread is the smallest unit of execution that your operating system can schedule. Multiple threads within the same program can run at the same time, sharing memory but each following its own sequence of instructions.

Threads let programs do multiple things simultaneously—keeping interfaces responsive, processing requests in parallel, and using multi-core CPUs effectively. Understanding threads is essential for writing fast, responsive software.

💡 If two threads touch the same variable and at least one writes, protect it with a lock—no exceptions.

Ask Codex about Thread →
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Always acquire locks in a consistent order. Set lock timeouts. Catch PDOException SQLSTATE 40001 and retry. Use optimistic locking to avoid locks entirely.
📦 Applies To
web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
lockForUpdate|SELECT.*FOR UPDATE
Auto-detectable: ✗ No
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Function Tests: Update
CWE-833


✓ schema.org compliant