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

PDO Transactions

PHP PHP 5.1+ Intermediate
debt(d9/e3/b3/t7)
d9 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production until users hit it' (d9). The detection_hints field explicitly states 'automated: no' and the code pattern (multiple execute() calls without transaction wrapping) produces no compiler error, no default linter warning, and no runtime exception — the database simply ends up in a partially corrupted state only visible when a mid-operation crash occurs in production.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix (replace pattern with safer alternative)' (e3). The quick_fix states 'Wrap multi-step operations in beginTransaction() / commit() with a catch block that calls rollBack()' — this is a small, localised refactor within the affected function or component, not a one-liner but not cross-cutting either.

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

Closest to 'localised tax' (b3). The choice applies to web and CLI contexts but is scoped to database-interaction code. Once correctly wrapped, transactions don't impose ongoing weight on unrelated parts of the codebase; the burden is felt only in DB-touching components.

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

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field directly identifies the trap: calling beginTransaction() twice appears to nest transactions (as supported in other databases or ORMs), but MySQL silently commits the first transaction instead — contradicting reasonable developer expectations about nesting behaviour and requiring SAVEPOINTs as a non-obvious workaround.

About DEBT scoring →

Also Known As

PDO beginTransaction PDO commit rollback database transactions PHP

TL;DR

PDO wraps multiple queries in an atomic unit — either all succeed or all roll back.

Explanation

beginTransaction() disables auto-commit. commit() writes all changes atomically. rollBack() undoes everything since beginTransaction(). PDO throws a PDOException if beginTransaction() is called when already in a transaction. Savepoints (SAVEPOINT name / ROLLBACK TO name) allow partial rollbacks within a transaction. MySQL requires InnoDB tables — MyISAM does not support transactions.

Diagram

sequenceDiagram
    participant PHP
    participant MySQL
    PHP->>MySQL: beginTransaction()
    PHP->>MySQL: UPDATE accounts SET balance=balance-100
    PHP->>MySQL: UPDATE accounts SET balance=balance+100
    alt success
        PHP->>MySQL: commit()
        MySQL-->>PHP: OK
    else exception
        PHP->>MySQL: rollBack()
        MySQL-->>PHP: reverted
    end

Common Misconception

Calling beginTransaction() twice nests transactions. MySQL does not support nested transactions — the second beginTransaction() silently commits the first. Use SAVEPOINTs for nested logic.

Why It Matters

Without transactions, a crash mid-operation leaves the database in a partially updated state — money transferred but not credited, orders created without inventory decremented.

Common Mistakes

  • Forgetting rollBack() in the catch block — failed transactions hold locks until the connection closes.
  • Using MyISAM tables which silently ignore transaction boundaries.
  • Opening long-running transactions that hold row locks and cause deadlocks under concurrency.

Avoid When

  • Avoid long-running transactions — they hold row locks and cause deadlocks under concurrency.
  • Do not open a transaction and then make external HTTP calls before committing — network failures leave transactions open.

When To Use

  • Use transactions for any operation that modifies multiple rows or tables that must succeed or fail together.
  • Use transactions for financial operations, inventory management, and any multi-step state change.

Code Examples

✗ Vulnerable
// No transaction — partial failure leaves DB inconsistent
$pdo->prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?')
    ->execute([$amount, $fromId]);
// Exception here? $fromId debited, $toId never credited.
$pdo->prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?')
    ->execute([$amount, $toId]);
✓ Fixed
$pdo->beginTransaction();
try {
    $pdo->prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?')
        ->execute([$amount, $fromId]);
    $pdo->prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?')
        ->execute([$amount, $toId]);
    $pdo->commit();
} catch (\Throwable $e) {
    $pdo->rollBack();
    throw $e;
}

Added 31 Mar 2026
Views 49
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 1 ping W 0 pings T 0 pings F 1 ping S 3 pings S 3 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 3 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Perplexity 6 Scrapy 6 Google 5 SEMrush 5 ChatGPT 4 Unknown AI 3 Ahrefs 3 Meta AI 2 Claude 1 Bing 1 Majestic 1 PetalBot 1
crawler 34 crawler_json 3 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Wrap multi-step operations in beginTransaction() / commit() with a catch block that calls rollBack()
📦 Applies To
PHP 5.1+ web cli
🔗 Prerequisites
🔍 Detection Hints
Multiple execute() calls without beginTransaction()/commit() wrapping
Auto-detectable: ✗ No
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update


✓ schema.org compliant