Thuta Learning
IntermediateData & Databasesbeginner

Transactions and ACID, Conceptually

What you'll walk away with

  • Explain the core ideas behind Transactions and ACID, Conceptually
  • Read the diagram/table and identify the shape of the data model, schema, or architecture
  • Explain how this concept or system choice applies to a real project

Build the mental model

A transaction groups multiple operations so they succeed or fail together - debiting Account A and crediting Account B must both happen.

BEGIN

Start a new transaction

Operation A + B

Run the debit and credit operations

COMMIT or ROLLBACK

COMMIT if everything succeeded, ROLLBACK if anything failed

  • Atomicity - all-or-nothing
  • Consistency - valid state to valid state
  • Isolation - concurrent transactions don't interfere unexpectedly
  • Durability - once committed, it stays committed

Concurrency - multiple users reading and writing at once - can cause problems like lost updates or stale reads.

Isolation controls how much transactions can see of each other. PostgreSQL's transaction/MVCC lessons and Redis's transaction lesson cover this hands-on.

Transaction
A group of database operations that succeed or fail together as one unit.
ACID
The four guarantees a transaction is expected to provide - Atomicity, Consistency, Isolation, Durability.
text
BANK TRANSFER TRANSACTION FLOW
------------------------------
BEGIN
  |
  v
Operation A: debit Account A  (balance -= amount)
  |
  v
Operation B: credit Account B (balance += amount)
  |
  v
Did both operations succeed and stay valid?
  |
  +--YES--> COMMIT   (both changes are kept)
  |
  +--NO ---> ROLLBACK (both changes undone,
                        as if nothing happened)

Connect it to a real scenario

Wrap related writes in a transaction whenever they must all succeed or fail together - creating an order plus decrementing stock, or transferring points, are typical cases.

Most frameworks and libraries provide a transaction helper, so you rarely write raw BEGIN/COMMIT/ROLLBACK by hand - but understanding what happens underneath still helps.

Be deliberate about what gets grouped - wrapping too much unrelated work in one long transaction can hurt concurrency.

The runnable example below simulates a bank-transfer transaction, rolling both balances back untouched if funds are insufficient.

Try the working example

javascript
function transferFunds(accounts, fromId, toId, amount) {
  const original = accounts.map((a) => ({ ...a }));
  const from = accounts.find((a) => a.id === fromId);
  const to = accounts.find((a) => a.id === toId);

  from.balance -= amount;
  to.balance += amount;

  if (from.balance < 0) {
    for (const a of accounts) {
      const o = original.find((x) => x.id === a.id);
      a.balance = o.balance;
    }
    return {
      status: "ROLLBACK",
      reason: "Insufficient funds",
      accounts: accounts.map((a) => ({ ...a })),
    };
  }

  return { status: "COMMIT", accounts: accounts.map((a) => ({ ...a })) };
}

const accountsA = [{ id: "A", balance: 500 }, { id: "B", balance: 100 }];
console.log("Successful transfer:", transferFunds(accountsA, "A", "B", 200));

const accountsB = [{ id: "A", balance: 50 }, { id: "B", balance: 100 }];
console.log("Rolled-back transfer:", transferFunds(accountsB, "A", "B", 200));
You should see
Successful transfer: { status: 'COMMIT', accounts: [ {id:'A',balance:300}, {id:'B',balance:300} ] }
Rolled-back transfer: { status: 'ROLLBACK', reason: 'Insufficient funds', accounts: [ {id:'A',balance:50}, {id:'B',balance:100} ] }

The first transfer succeeds because A had 500. The second would push A's balance negative, so both balances are rolled back to their original values instead.

5-minute try-it

Extend transferFunds to also push into a transferHistory log array - add an entry on every COMMIT, and add nothing on a ROLLBACK.

One important caution

Leaving related writes ungrouped, which risks half-completed updates when one step fails

Bundling too much unrelated work into one long transaction, unnecessarily hurting concurrency

Wikipedia: ACIDHow Databases Work

Easy traps

  • Leaving related writes ungrouped, which risks half-completed updates when one step fails
  • Bundling too much unrelated work into one long transaction, unnecessarily hurting concurrency
  • This course teaches database concepts and the product landscape at a framework-neutral level -- for hands-on SQL syntax or PostgreSQL/MongoDB/Redis depth, continue to the SQL, PostgreSQL, MongoDB, or Redis tutorials.

Exercise

Extend transferFunds to also push into a transferHistory log array - add an entry on every COMMIT, and add nothing on a ROLLBACK.

You'll know it worked when: Successful transfer: { status: 'COMMIT', accounts: [ {id:'A',balance:300}, {id:'B',balance:300} ] } Rolled-back transfer: { status: 'ROLLBACK', reason: 'Insufficient funds', accounts: [ {id:'A',balance:50}, {id:'B',balance:100} ] } The first transfer succeeds because A had 500. The second would push A's balance negative, so both balances are rolled back to their original values instead.

Transactions and ACID, Conceptually | Thuta Learning