BEGIN, COMMIT, ROLLBACK și SAVEPOINT în PostgreSQL

Modificare date și tranzacții PostgreSQL 8.0+ (standard în PostgreSQL 15–17)

Controlează tranzacțiile ACID și punctele intermediare de salvare (SAVEPOINT) pentru recuperarea din erori.

Sintaxă SQL
BEGIN;nSAVEPOINT sp1;n-- interogări SQLnROLLBACK TO SAVEPOINT sp1;nCOMMIT;

Ce face BEGIN, COMMIT, ROLLBACK și SAVEPOINT

În PostgreSQL, fiecare instrucțiune individuală rulează implicit în propria tranzacție (autocommit). Pentru a grupa mai multe operații într-o unitate atomică (totul sau nimic), deschizi un bloc cu BEGIN (sau START TRANSACTION) și îl finalizezi cu COMMIT sau îl anulezi cu ROLLBACK. În PostgreSQL, chiar și comenzile DDL (CREATE TABLE, ALTER TABLE, DROP INDEX) sunt tranzacționale și pot fi anulate cu ROLLBACK!

O particularitate importantă a lui PostgreSQL este că orice eroare SQL apărută în interiorul unui bloc BEGIN marchează întreaga tranzacție ca abortată: comenzile ulterioare vor fi refuzate cu ERROR: current transaction is aborted până la un ROLLBACK sau ROLLBACK TO SAVEPOINT.

Clauze, operatori și argumente

Clauză / Operator Descriere
BEGIN [ISOLATION LEVEL ...] Deschide o tranzacție nouă (niveluri: READ COMMITTED implicit, REPEATABLE READ, SERIALIZABLE).
COMMIT Salvează permanent toate modificările efectuate în tranzacția curentă.
ROLLBACK Anulează toate modificările făcute de la BEGIN și readuce baza de date la starea inițială.
SAVEPOINT nume_punct Creează un punct de control în interiorul tranzacției curente.
ROLLBACK TO SAVEPOINT nume Anulează doar modificările efectuate după acel SAVEPOINT și curăță starea de eroare a tranzacției.

Exemple

Exemplul 1: Transfer bancar atomic între două conturi cu BEGIN și COMMIT

Scădem 500 RON dintr-un cont și îi adăugăm în altul; ambele modificări devin vizibile simultan doar la COMMIT.

BEGIN;

UPDATE conturi SET sold = sold - 500.00 WHERE id = 10;
UPDATE conturi SET sold = sold + 500.00 WHERE id = 20;

INSERT INTO jurnal_transferuri (sursa_id, destinatie_id, suma)
VALUES (10, 20, 500.00);

COMMIT;

Rezultat interogare

BEGIN
UPDATE 1
UPDATE 1
INSERT 0 1
COMMIT

Exemplul 2: Recuperarea dintr-o eroare fără pierderea întregii tranzacții folosind SAVEPOINT

Creăm o comandă, apoi încercăm să aplicăm un cupon; dacă apare o constrângere încălcată, revenim cu ROLLBACK TO SAVEPOINT și păstrăm comanda validă.

BEGIN;

INSERT INTO comenzi (id, client_id, total_lei) VALUES (6001, 101, 250.00);
SAVEPOINT inainte_de_cupon;

-- Această operație poate eșua (ex: cupon expirat sau cheie duplicată)
INSERT INTO cupoane_folosite (comanda_id, cod_cupon) VALUES (6001, 'EXPIRAT');
-- În caz de eroare, revenim la savepoint și continuăm tranzacția:
ROLLBACK TO SAVEPOINT inainte_de_cupon;

COMMIT;

Rezultat interogare

BEGIN
INSERT 0 1
SAVEPOINT
ERROR:  check constraint "cupon_activ_chk" is violated
ROLLBACK
COMMIT

Greșeli frecvente

  • Uitatul unei tranzacții deschise în starea idle in transaction: aceasta blochează procesul VACUUM să curețe rândurile moarte și păstrează lacătele active; configurează idle_in_transaction_session_timeout în producție.
  • Încercarea de a rula alte interogări după o eroare fără ROLLBACK TO SAVEPOINT: în PostgreSQL, chiar dacă trimiți COMMIT la finalul unei tranzacții cu eroare, Postgres execută automat un ROLLBACK.

Comenzi și funcții înrudite

  • INSERT INTO ... RETURNING: Inserează unul sau mai multe rânduri și returnează imediat valorile generate (ID-uri, timestamp-uri) fără o interogare suplimentară.
  • ON CONFLICT DO UPDATE (UPSERT): Rezolvă atomic conflictele de cheie unică la inserare: ignoră rândul duplicat sau îl actualizează pe loc.
  • DELETE ... USING și TRUNCATE: Șterge rânduri filtrate prin joncțiuni cu DELETE … USING sau golește instantaneu tabele întregi cu TRUNCATE.