Transakcja

Niepodzielna jednostka pracy w bazie, wykonana w całości albo wcale. Grupuje kilka operacji, by baza pozostawała w spójnym stanie.

Transakcja to niepodzielna jednostka pracy w bazie danych: zestaw operacji, który wykonuje się w całości albo wcale. Jeśli cokolwiek pójdzie nie tak w trakcie, baza cofa wszystkie zmiany do stanu sprzed startu, jakby nic się nie wydarzyło. Dzięki temu dane nie zostają w połowicznym, niespójnym stanie — a o to właśnie chodzi.

Klasyczny przykład to przelew. Zdejmujesz 100 zł z konta A i dodajesz 100 zł do konta B. To dwie osobne operacje UPDATE, ale logicznie jedna całość. Gdyby pierwsza się udała, a druga padła (np. serwer się wyłączył w połowie), pieniądze wyparowałyby z systemu. Transakcja temu zapobiega: albo zaksięgują się obie zmiany, albo żadna.

Jak to działa

Transakcję otwierasz, wykonujesz operacje i na koniec ją zatwierdzasz (COMMIT) albo cofasz (ROLLBACK). Do momentu COMMIT zmiany są „tymczasowe” — inni użytkownicy zwykle ich nie widzą, a baza trzyma sposób na ich wycofanie.

Transakcje opisuje się skrótem ACID: Atomicity (wszystko albo nic), Consistency (baza przechodzi z jednego poprawnego stanu w drugi, reguły i constrainty zostają zachowane), Isolation (równoległe transakcje nie depczą sobie po danych) i Durability (po COMMIT zmiany przetrwają nawet zanik zasilania). To fundament, na którym stoją bazy relacyjne jak PostgreSQL, MySQL (silnik InnoDB) czy Oracle.

Przykład z praktyki

W PostgreSQL przez psql wygląda to tak:

  1. BEGIN; — start transakcji
  2. UPDATE konta SET saldo = saldo - 100 WHERE id = 1;
  3. UPDATE konta SET saldo = saldo + 100 WHERE id = 2;
  4. COMMIT; — zatwierdzenie obu zmian naraz

Jeśli między krokami zorientujesz się, że coś jest nie tak, wpisujesz ROLLBACK; i baza wraca do punktu wyjścia. Możesz też ustawiać SAVEPOINT, żeby cofać się tylko do wybranego momentu, a nie na sam początek.

Na co uważać

Pierwszy mit: „transakcja sama się zapisze”. Nie — bez COMMIT (albo autocommit, który wiele klientów ma domyślnie włączony) zmiany mogą zniknąć przy rozłączeniu. Drugi błąd to trzymanie transakcji otwartej godzinami — blokady (locks) na wierszach potrafią zablokować innych i wywołać deadlock. Trzymaj transakcje krótkie.

Trzecia pułapka: nie wszystko jest transakcyjne. W MySQL silnik MyISAM transakcji nie obsługuje, a w wielu bazach polecenia DDL (CREATE, DROP) potrafią niejawnie zatwierdzić bieżącą transakcję. Sprawdzaj, z czym pracujesz.

Pojęcia powiązane: ACID, COMMIT i ROLLBACK, poziomy izolacji (isolation levels), blokady i deadlock, dirty read, SAVEPOINT, spójność danych.