HeadlinesBriefing favicon HeadlinesBriefing.com

Why a Simple Money‑Transfer Query Can Break Relational Databases

Hacker News •
×

A simple TSQL money‑transfer routine that checks Alice’s balance before moving ten dollars to Bob looks innocent, yet it hides three classic concurrency failures. Without a surrounding transaction, a crash can leave Alice’s account debited while Bob receives nothing. Wrapping the logic in BEGIN TRANSACTION … COMMIT restores atomicity and keeps the ledger balanced despite crashes entirely.

Running two transfers concurrently exposes a TOCTOU bug: each transaction reads Alice’s balance before either withdraws, so both may pass the ≥10 check and overdraw the account. Adding an UPDLOCK hint forces a row‑level lock during the SELECT, preventing other sessions from reading the stale balance until the first transaction commits before the transaction finishes.

If Alice and Bob swap directions simultaneously, each transaction locks its source row first, then waits on the other’s lock, creating a deadlock. Pre‑locking both rows in a single statement avoids the cycle but inflates code size by about 50 %. The author argues that a Rust‑inspired, “fearless concurrency” SQL database could make atomicity and lock safety defaults, sacrificing raw throughput for correctness.