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

Database Transactions

database PHP 5.1+ Intermediate
debt(d5/e3/b5/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5). The detection_hints specify semgrep and phpstan can detect 'multiple related DB writes without PDO transaction wrapping' and 'no rollback in catch block'. These are specialist static analysis tools, not default linters, and the pattern requires semantic understanding of related writes.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes a clear pattern: wrap in try/catch with beginTransaction, rollback in catch, commit after success. This is a small refactor within one component — adding transaction boundaries around existing code — but may touch multiple methods/files if operations are spread across service classes.

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

Closest to 'persistent productivity tax' (b5). Transactions apply across web, cli, and queue-worker contexts per applies_to. Once a codebase establishes transaction patterns (or fails to), it affects every data-modifying operation. Poor transaction hygiene compounds: lock contention, deadlocks, timeout cascades ripple through the system. Not architecture-defining, but a persistent concern in every DB operation.

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

Closest to 'notable trap' (t5). The misconception explicitly states developers believe 'wrapping everything in a transaction guarantees data integrity' when in fact long transactions cause locks, deadlocks, and timeout cascades. This is a documented gotcha — transactions should be short, business logic outside. Most experienced PHP devs eventually learn this the hard way through production lock contention.

About DEBT scoring →

Also Known As

database transactions BEGIN COMMIT ROLLBACK transaction isolation

TL;DR

A sequence of SQL operations treated as a single atomic unit — all succeed or all roll back — enforcing ACID guarantees.

Explanation

A transaction wraps multiple SQL statements so they either all commit or all roll back on error. In PHP with PDO: $pdo->beginTransaction(); ... $pdo->commit(); with $pdo->rollBack() in a catch block. Key behaviours: implicit vs explicit transactions (autocommit mode), savepoints for nested rollback to a known point, and isolation levels controlling visibility of concurrent changes. Transaction scope should be as short as possible — open transactions hold locks. Avoid transactions spanning HTTP requests (leave a transaction open between user steps). Doctrine's EntityManager::flush() wraps all pending changes in one transaction. Eloquent's DB::transaction(fn) automatically retries on deadlock up to a configurable count.

Diagram

sequenceDiagram
    participant APP as Application
    participant DB as Database
    APP->>DB: BEGIN TRANSACTION
    APP->>DB: INSERT INTO orders values
    APP->>DB: UPDATE inventory SET stock=stock-1
    APP->>DB: INSERT INTO payments values
    Note over APP,DB: All or nothing
    APP->>DB: COMMIT
    DB-->>APP: Success - all 3 rows written
    Note over APP,DB: On failure
    APP->>DB: BEGIN
    APP->>DB: INSERT order
    APP->>DB: UPDATE inventory - fails!
    APP->>DB: ROLLBACK
    DB-->>APP: Nothing written - consistent state

Common Misconception

Wrapping everything in a transaction guarantees data integrity. Transactions provide ACID guarantees, but long-running transactions hold locks, increase deadlock risk, and can cause timeout cascades. Transactions should be as short as possible — business logic and external calls should happen outside transaction boundaries.

Why It Matters

Database transactions group multiple operations into an atomic unit — if any step fails, the whole transaction rolls back, preventing partial updates that leave data in an inconsistent state.

Common Mistakes

  • Multi-step operations not wrapped in a transaction — a crash between steps corrupts data.
  • Transactions that span user interactions (long transactions) — lock contention degrades performance.
  • Catching exceptions inside a transaction and continuing instead of rolling back.
  • Not using transactions for read-modify-write sequences — race conditions occur without locking.

Avoid When

  • Long-running transactions that hold locks for seconds — other queries queue behind and throughput drops.
  • Transactions spanning multiple microservices — use saga patterns or two-phase commit instead.
  • Read-only operations that need no consistency guarantees — transactions add overhead with no benefit.
  • Transactions containing external HTTP calls — the network call can hang while locks are held indefinitely.

When To Use

  • Any operation that modifies multiple rows or tables that must succeed or fail together.
  • Financial operations — debiting one account and crediting another must be atomic.
  • Preventing partial writes that leave data in an inconsistent state.
  • Operations that check a condition and act on it — wrap the check and write together to prevent TOCTOU races.

Code Examples

✗ Vulnerable
// No transaction — if second query fails, first already committed
$pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
$pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
✓ Fixed
try {
    $pdo->beginTransaction();
    $pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
    $pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
    $pdo->commit();
} catch (\Throwable $e) {
    $pdo->rollBack();
    throw $e;
}

Added 15 Mar 2026
Edited 25 Mar 2026
Views 36
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 0 pings S 1 ping M 1 ping 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 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S
No pings yet today
Perplexity 11 Amazonbot 9 Unknown AI 3 Ahrefs 2 SEMrush 2 Google 1 Majestic 1 ChatGPT 1
crawler 29 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Use try/catch around PDO transactions: beginTransaction in try, rollback in catch, commit only after all operations succeed — never commit on exception
📦 Applies To
PHP 5.1+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Multiple related DB writes without PDO transaction wrapping; no rollback in catch block
Auto-detectable: ✓ Yes semgrep phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-362

✓ schema.org compliant