PrepZone Logo
PrepZone

ACID Transactions Explained

Atomicity, consistency, isolation, durability — with a checkout example that must not half-succeed.

Read these first

Why this matters

  • Partial checkouts — payment captured but inventory not decremented — are customer-support nightmares and revenue reconciliation failures.
  • ACID is the vocabulary senior engineers use when discussing correctness under concurrency and crashes.
  • Spring's @Transactional wraps JDBC calls, but the guarantees come from the database engine, not the annotation alone.
  • Misunderstanding isolation leads to duplicate charges, lost updates, and phantom inventory counts.
AtomicityAll or nothing
ConsistencyValid state to valid state
IsolationConcurrent txs don't interfere
DurabilityCommitted survives crash
Atomicity, consistency, isolation, durability — the contract relational transactions offer.

Atomicity: all or nothing

Atomicity means the transaction is an indivisible unit. VaultCommerce's checkout stored procedure logic in SQL:

Java
BEGIN;

INSERT INTO payments (order_id, amount_cents, status)
VALUES (5001, 15999, 'CAPTURED');

UPDATE orders SET status = 'PAID' WHERE id = 5001;

UPDATE products SET stock = stock - 1
WHERE id = 881 AND stock >= 1;

-- If stock update affects 0 rows, application rolls back:
COMMIT;  -- or ROLLBACK;

If any statement fails — network blip, constraint violation, insufficient stock — ROLLBACK undoes every change in the block. The customer is not charged for an order that was never fulfilled.

Consistency: rules always hold

Consistency means every committed state satisfies defined rules — constraints, triggers, and business invariants. VaultCommerce enforces:

Java
ALTER TABLE order_items
  ADD CONSTRAINT positive_qty CHECK (quantity > 0);

ALTER TABLE order_items
  ADD CONSTRAINT fk_product
  FOREIGN KEY (product_id) REFERENCES products(id);

A transaction that would leave quantity = 0 or reference a deleted product is rejected. Consistency is about valid states, not "every replica agrees instantly" (that is a distributed-systems nuance for later modules).

Isolation: concurrent sessions do not corrupt each other

Isolation controls how much one transaction sees of another's in-progress work. Two customers buying the last unit of a limited-edition SKU must not both succeed.

Java
-- Session A                          -- Session B
BEGIN;                                 BEGIN;
SELECT stock FROM products
  WHERE id = 881;  -- returns 1
                                       SELECT stock FROM products
                                         WHERE id = 881;  -- returns 1
UPDATE products SET stock = 0
  WHERE id = 881;
COMMIT;
                                       UPDATE products SET stock = -1
                                         WHERE id = 881;
                                       COMMIT;  -- oversell without proper isolation

Postgres default READ COMMITTED plus row-level locking on UPDATE ... WHERE stock >= 1 prevents the oversell. Isolation levels and MVCC are covered in depth in a later article.

Durability: committed means survived

Durability guarantees that once COMMIT succeeds, the data survives a crash — even if power fails milliseconds later. Postgres writes WAL records to disk (or replicates them) before acknowledging commit.

VaultCommerce's RDS instance uses synchronous replication to a standby in another availability zone. A committed order survives single-node failure.

ACID at a glance

  • Atomicity — All statements commit or none do.
  • Consistency — Committed data obeys constraints and invariants.
  • Isolation — Concurrent transactions do not produce invalid interleavings.
  • Durability — Committed data survives crashes after acknowledgment.

ACID in Spring Boot

Java
@Service
public class CheckoutService {
    @Transactional
    public OrderResult checkout(CheckoutRequest req) {
        Order order = orderRepo.save(new Order(req.getCustomerId()));
        paymentClient.capture(order.getId(), req.getAmount());
        inventoryService.decrementStock(req.getProductId(), req.getQty());
        return OrderResult.success(order.getId());
    }
}

@Transactional begins a transaction at method entry and commits on normal return. An uncaught exception triggers rollback. External HTTP calls inside the transaction extend lock duration — VaultCommerce moved payment capture after commit using transactional outbox for safer boundaries.

Quick recall

Everything you need if you only revisit this box.

  • Transactions bundle operations into one commit-or-rollback unit.
  • Atomicity prevents half-finished checkouts; consistency enforces constraints.
  • Isolation protects concurrent buyers from overselling the last item.
  • Durability means committed orders survive crashes via WAL and replication.
  • @Transactional delegates to the database — design transaction boundaries around short, local work.

Test yourself

Answer these before moving on — recall is what makes it stick.