Picture a scene. A customer orders, your code adds a row to the orders table, and right before reducing the stock the server crashes. The result: the order exists, but the stock never went down - the accounts do not match. Or the money got deducted but the order was never created. This 'half-finished' work is the backend's most frightening bug, because it quietly corrupts data.
Transactions solve this problem. A group of jobs is bundled together - either all of them happen, or none of them do. If any step in the middle fails, the whole thing rolls back to the earlier state, as if nothing happened.
await db.$transaction(async (tx) => {
const order = await tx.order.create({ data: { userId, total } });
await tx.product.update({
where: { id: productId },
data: { stock: { decrement: quantity } },
});
await tx.payment.create({ data: { orderId: order.id, amount: total } });
});
// If any step errors, the whole thing rolls backACID - the name of four qualities
- Atomicity - everything happens, or nothing does. That is the main point of today's chapter.
- Consistency - every transaction takes the database from one valid state to another valid state, breaking no rules.
- Isolation - transactions running together cannot see each other's half-done work.
- Durability - once committed, the data stays, even if the server crashes.
The easy rule for knowing when you need a transaction: when one job involves multiple tables or multiple steps, and stopping in the middle would break the accounts - money, orders, stock, balances - never write code there without a transaction. Just reading one row or updating one field does not need it.
The mistake everyone makes
The costliest mistake: doing money or stock work with step-by-step separate queries, with no arrangement to catch an error in the middle. The bug may happen once a month, but every time it leaves a mess in the accounts that is almost impossible to track down.
Today's practice
Wrap your project's order-creation flow in a transaction. Then deliberately cause an error in a middle step (like a non-existent product id) and verify - no row was saved in the orders table, and the stock did not change either.
How to say it in an interview
With transactions I make a group of jobs atomic - either everything happens, or it rolls back and nothing happens. For money, orders and stock this is mandatory, because half-done work means broken accounts. The other ACID qualities - consistency, isolation, durability - make sure data stays correct even when many requests arrive together.