Transaction
“A transaction is a unit of work that you want to treat as ‘a whole.’ It has to either happen in full or not at all.” — Martin Kleppmann, Designing Data-Intensive Applications
Understand This First
- Atomic – transactions provide atomicity for groups of operations.
- Database – transactions are implemented by the database engine.
- State – transactions protect state from corruption during multi-step changes.
Context
When an application performs multiple related operations on a Database (creating an order and decrementing inventory, transferring money between accounts, updating a user profile across several tables), those operations need to succeed or fail as a unit. A transaction is the mechanism that provides this guarantee. This is an architectural pattern because transactions are the primary tool for maintaining Consistency and Atomic behavior in data systems.
Problem
How do you ensure that a group of related data operations either all succeed or all fail, even in the face of crashes, errors, and concurrent access?
Without transactions, a multi-step operation can leave data in an inconsistent state. An error during step three of a five-step process means steps one and two took effect but steps four and five didn’t. The system is now in a state that no user action produced and no developer anticipated. Debugging this kind of corruption is among the most difficult work in software.
Forces
- Multi-step operations are common. Most real business logic involves changing more than one record.
- Crashes and errors can happen at any point during execution.
- Multiple users operating concurrently can interfere with each other’s in-progress work.
- Transactions add overhead and can create contention, reducing throughput.
- Transactions within a single database are well supported; transactions spanning multiple systems are hard.
Solution
Wrap related operations in a database transaction. The database guarantees four properties, known as ACID:
- Atomicity: All operations in the transaction complete, or none of them do. If anything fails, all changes are rolled back.
- Consistency: The transaction moves the database from one valid state to another. Constraints (foreign keys, uniqueness, check constraints) are enforced.
- Isolation: Concurrent transactions behave as if they ran one at a time. One transaction doesn’t see another’s half-finished work.
- Durability: Once a transaction commits, its changes survive crashes, power failures, and restarts.
In practice, using transactions looks like this: begin the transaction, perform your operations, and either commit (make all changes permanent) or roll back (undo all changes). Most database libraries and ORMs provide a simple way to do this:
begin transaction
create order record
decrement inventory
charge payment
commit transaction
If the payment charge fails, the order record and inventory decrement are automatically rolled back. The database returns to the state it was in before the transaction began.
How It Plays Out
A ride-sharing app assigns a driver to a ride. The operation involves updating the ride status, the driver’s availability, and creating a notification record. Without a transaction, a crash after updating the ride status but before updating the driver means the driver appears available but is actually assigned to a ride. With a transaction, all three updates either commit together or none of them do.
AI agents frequently generate code that performs multiple database writes without transaction boundaries. The code works during development because crashes and concurrency are rare, but it fails under production conditions. When reviewing agent-generated code that touches a database, ask: “If this code crashed halfway through, what state would the data be in?” If the answer is “a mess,” wrap the operations in a transaction.
Transactions that hold locks for a long time, especially those that make HTTP calls inside a transaction, can cause other operations to wait or time out. Keep transactions short: do your computation outside the transaction, then execute the database operations quickly inside it.
“The ride assignment involves three writes: update the ride status, mark the driver unavailable, and create a notification. Wrap all three in a single database transaction.”
Consequences
Transactions give you confidence that multi-step operations are safe. They eliminate a large category of data corruption bugs. They let you reason about correctness in terms of complete operations rather than individual statements. ACID guarantees mean you can trust that committed data is real and complete.
The costs are performance and complexity. Transactions require the database to maintain locks and logs, which reduces throughput under heavy load. Long or contended transactions can cause other operations to block. Transactions across multiple databases or services (distributed transactions) are notoriously difficult and often avoided in favor of alternative patterns like sagas or compensating actions. Using transactions correctly also requires understanding isolation levels. Most databases default to a level that permits some subtle anomalies unless you explicitly choose a stricter setting.
Related Patterns
Sources
- Jim Gray’s “The Transaction Concept: Virtues and Limitations” (Tandem Technical Report TR 81.3; presented at VLDB 1981) is the founding paper that crystallized the transaction as a unit of work — a state transformation that is atomic, durable, and consistent. The Solution section’s framing of a transaction as a wrapper that either commits a group of operations together or rolls them all back is Gray’s definition restated for working programmers.
- Theo Härder and Andreas Reuter coined the ACID acronym in “Principles of Transaction-Oriented Database Recovery” (ACM Computing Surveys, vol. 15, no. 4, 1983, pp. 287–317). The four properties listed in the Solution — atomicity, consistency, isolation, durability — are theirs verbatim, as is the conceptual frame this article uses to teach what a transaction guarantees.
- Jim Gray and Andreas Reuter’s Transaction Processing: Concepts and Techniques (Morgan Kaufmann, 1992) is the comprehensive treatment of the field — locks, logs, isolation levels, recovery, and the engineering tradeoffs the Consequences section gestures at. The article’s warnings about long-held locks, contention, and the difficulty of distributed transactions all draw on territory mapped in this book.
- Martin Kleppmann’s Designing Data-Intensive Applications (O’Reilly, 2017; 2nd ed. 2025) supplies the article’s epigraph and frames transactions for a modern audience working across single-node and distributed systems. Chapter 7 is the accessible entry point this article points readers toward when they want more depth on isolation levels and the subtle anomalies the Consequences section flags.
- Hector Garcia-Molina and Kenneth Salem’s “Sagas” (ACM SIGMOD, 1987, pp. 249–259) introduced the compensating-action pattern the Consequences section names as the alternative to distributed transactions. The article’s recommendation to “favor sagas or compensating actions” over multi-system transactions is a direct descendant of Garcia-Molina and Salem’s argument that long-lived transactions are better expressed as sequences of smaller transactions with compensations.