By default, each SQL query runs in its own transaction. Consider Figures
and , which show two identical queries.
test=> INSERT INTO trans_test VALUES (1);
INSERT 130057 1
test=> BEGIN WORK;
BEGIN
test=> INSERT INTO trans_test VALUES (1);
INSERT 130058 1
test=> COMMIT WORK;
COMMIT
Figure is a typical INSERT query. Before POSTGRESQL starts the INSERT, it begins a transaction. It performs the INSERT, then commits the transaction. This step occurs automatically for any query with no explicit transaction. In Figure , the INSERT uses an explicit transaction. BEGIN WORK starts the transaction, and COMMIT WORK commits the transaction. The only difference between the two queries is that an implied BEGIN WORK...COMMIT WORK surrounds the first INSERT.
Even more valuable is the ability to bind multiple queries into a single transaction.
In such a case, either all queries execute to completion or none has any effect.
As an example, Figure shows two INSERTs
in a transaction.
test=> BEGIN WORK;
BEGIN
test=> INSERT INTO trans_test VALUES (1);
INSERT 130059 1
test=> INSERT INTO trans_test VALUES (2);
INSERT 130060 1
test=> COMMIT WORK;
COMMIT
PostgreSQL guarantees that either both INSERTs succeed or neither.
As a more complicated example, suppose you have a table of bank account balances,
and you wish to transfer $100 from one account to another account. This operation
is performed using two queries: an UPDATE to subtract $100 from one
account, and an UPDATE to add $100 to another account. The
UPDATEs should either both complete or have no effect. If the first
UPDATE completes but not the second, the $100 would disappear from
the bank records. It would have been subtracted from one account, but never
added to the other account. Such errors are very hard to find. Multistatement
transactions prevent them from happening. Figure
shows the two queries bound into a single transaction.
test=> BEGIN WORK;
BEGIN
test=> UPDATE bankacct SET balance = balance - 100 WHERE acctno = '82021';
UPDATE 1
test=> UPDATE bankacct SET balance = balance + 100 WHERE acctno = '96814';
UPDATE 1
test=> COMMIT WORK;
COMMIT
The transaction forces POSTGRESQL to perform the queries as a single operation.
When you begin a transaction
with BEGIN WORK, you do not have to commit it using COMMIT
WORK. Instead, you can close the transaction with ROLLBACK WORK
and the transaction will be discarded. The database is left as though the transaction
had never been executed. In Figure , the current
transaction is rolled back, causing the DELETE to have no effect.
test=> INSERT INTO rollback_test VALUES (1);
INSERT 19369 1
test=> BEGIN WORK;
BEGIN
test=> DELETE FROM rollback_test;
DELETE 1
test=> ROLLBACK WORK;
ROLLBACK
test=> SELECT * FROM rollback_test;
x
---
1
(1 row)
Likewise, if any query inside a multistatement transaction cannot be executed due to an error, the entire transaction is automatically rolled back.