W PostgreSQL NIE MA prawdziwych zagnieżdżonych transakcji w takim klasycznym sensie. Jest tylko zewnętrzna transakcja i "warstwy" punktów zapisu w jej środku.
Termin "zagnieżdżone transakcje" w PostgreSQL zwykle oznacza użycie punktów zapisu (savepoints) przez komendy SAVEPOINT, ROLLBACK TO SAVEPOINT, RELEASE SAVEPOINT. To nie są osobne niezależne transakcje, tylko specjalne checkpointy w jednej zewnętrznej transakcji, do których możesz się cofnąć bez wycofywania wszystkiego.
Analogicznie do życia: piszesz długi tekst w edytorze i co jakiś czas robisz ctrl+s. Jak coś popsujesz, możesz wrócić do jednej z wcześniejszych zapisanych wersji, nie tracąc całego progresu.
Komendy do ogarniania punktów zapisu
Do zarządzania zagnieżdżonymi transakcjami PostgreSQL daje trzy główne komendy:
SAVEPOINT
Ta komenda służy do tworzenia "punktów zapisu", do których możesz się cofnąć, jak zajdzie taka potrzeba. Taki punkt działa jak checkpoint w naszej transakcji.
SAVEPOINT mypoint;
ROLLBACK TO SAVEPOINT
Cofa część zmian zrobionych po wskazanym punkcie, zostawiając wcześniejsze zmiany w tej samej zewnętrznej transakcji nietknięte.
ROLLBACK TO SAVEPOINT mypoint;
RELEASE SAVEPOINT
Usuwa punkt zapisu. Po tym już nie możesz się do niego cofnąć.
RELEASE SAVEPOINT mypoint;
Przykład: dodawanie danych do kilku tabel z możliwością cofnięcia
Załóżmy, że robisz system zarządzania zamówieniami, gdzie trzeba zapisać dane naraz do dwóch tabel: orders i order_items. Błąd przy dodawaniu do jednej tabeli nie powinien powodować cofnięcia danych z drugiej.
BEGIN; -- Start transakcji
-- Tworzymy punkt zapisu
SAVEPOINT before_order;
-- Dodajemy zamówienie do tabeli orders
INSERT INTO orders (order_id, customer_id, date)
VALUES (1, 101, CURRENT_DATE);
-- Jeśli tu pojawi się błąd — cofamy się
SAVEPOINT before_order_items;
-- Dodajemy produkty do tabeli order_items
INSERT INTO order_items (order_id, product_id, quantity)
VALUES (1, 2001, 4);
-- Jak coś pójdzie nie tak
-- ROLLBACK TO SAVEPOINT before_order_items;
-- Zatwierdzamy transakcję (commitujemy zmiany)
COMMIT;
Jeśli na etapie dodawania rekordów do order_items pojawi się błąd, możesz się cofnąć do punktu before_order_items, a zmiany w tabeli orders zostaną zachowane.
Praktyczne tipy i typowe wtopy
Teraz, kiedy już ogarniasz jak działają komendy SAVEPOINT i ROLLBACK TO SAVEPOINT, parę rad, żeby nie wpaść w kłopoty:
- Nazwy punktów zapisu. Używaj czytelnych i unikalnych nazw dla
SAVEPOINT. Na przykładbefore_insert,step1i tak dalej — to mega pomaga przy debugowaniu. - Nie zapominaj zwalniać
SAVEPOINT. Jeśli już nie planujesz wracać do punktu, usuwaj go przezRELEASE SAVEPOINT, żeby nie zaśmiecać transakcji. - Zagnieżdżona transakcja ≠ osobna transakcja. Pamiętaj, że po komendzie
COMMITwszystkie punkty zapisu znikają. Jak zrobisz zewnętrznyCOMMIT, już nie ma odwrotu. - Blokowanie danych. Nawet jeśli cofniesz się do punktu, blokady rekordów ustawione w ramach transakcji zostają. To ważne, szczególnie jak pracujesz w środowisku z wieloma userami.
Zagnieżdżone transakcje z użyciem SAVEPOINT i ROLLBACK TO SAVEPOINT dają programistom mocne narzędzie do ogarniania trudnych sytuacji. Teraz możesz dzielić transakcje na elastyczne etapy, sprytnie obsługiwać błędy i unikać niepotrzebnego cofania danych. Pamiętaj, że jak widzisz słowo "cofnij", to nie zawsze powód do paniki: czasem cofnięcie to najlepszy sposób, żeby ruszyć dalej.
GO TO FULL VERSION