Skip to content

Transaction basics

A transaction turns several statements into one indivisible unit. You open it with BEGIN, run the statements you want grouped, and then close it with COMMIT to keep the work or ROLLBACK to discard it. Nothing inside the transaction is visible to other connections until you commit.

We will use a small accounts table for every example in this lesson.

CREATE TABLE accounts (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
owner text NOT NULL,
balance numeric NOT NULL CHECK (balance >= 0)
);
INSERT INTO accounts (owner, balance) VALUES ('Ada', 500), ('Linus', 100);

Moving 100 from Ada to Linus is two updates that must happen together. If the server crashed between them, atomicity guarantees neither change survives, so money is never created or destroyed.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE owner = 'Ada';
UPDATE accounts SET balance = balance + 100 WHERE owner = 'Linus';
COMMIT;

After the commit, the balances reflect both updates together.

id | owner | balance
----+-------+---------
1 | Ada | 400
2 | Linus | 200
(2 rows)

If anything looks wrong before you commit, ROLLBACK discards every change made since BEGIN, as if the transaction never ran. Here Ada lacks the funds, so we throw the whole thing away.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE owner = 'Ada';
-- on reflection, cancel everything:
ROLLBACK;

Every transaction follows the same path: it begins, runs its statements, and ends in exactly one of two ways. There is no in-between state once you decide.

flowchart TD
  A[BEGIN] --> B[Run statements]
  B --> C{Everything correct?}
  C -->|Yes| D[COMMIT: changes become permanent]
  C -->|No| E[ROLLBACK: changes discarded]
  D --> F[Transaction ends]
  E --> F
A transaction begins, runs, and either commits or rolls back

Sometimes you want to undo only part of a transaction without abandoning the rest. A SAVEPOINT is a named marker inside the transaction; ROLLBACK TO rewinds to that marker, keeping everything before it and discarding everything after.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE owner = 'Ada';
SAVEPOINT after_debit;
UPDATE accounts SET balance = balance + 100 WHERE owner = 'Nobody';
-- that owner does not exist; undo just the second update:
ROLLBACK TO after_debit;
UPDATE accounts SET balance = balance + 100 WHERE owner = 'Linus';
COMMIT;

The debit and the final credit are kept; only the work between the savepoint and ROLLBACK TO is thrown away.

owner | balance
-------+---------
Ada | 400
Linus | 200
(2 rows)
  • Keep transactions short. A transaction that stays open holds resources and, as the MVCC lesson shows, can hold back cleanup of old row versions.
  • By default a connection is in auto-commit mode: each lone statement is its own committed transaction. You only leave that mode by issuing BEGIN.
  • An error inside a transaction puts it into an aborted state; PostgreSQL then rejects further commands until you ROLLBACK (or ROLLBACK TO a savepoint).
  • In application code, always pair BEGIN with a ROLLBACK on the error path. The driver examples above show the try-or-finally pattern that guarantees the connection never leaks an open transaction.
What does ROLLBACK do to the statements run since BEGIN?
What is the purpose of a SAVEPOINT?
When is a single statement run on its own committed automatically?