Menu

SAVEPOINT w SQLite: zagnieżdżone transakcje z ROLLBACK TO

Jak działają savepointy w SQLite: nazwane znaczniki wewnątrz transakcji, do których możesz się wycofać bez wyrzucania całej transakcji.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Savepoint to nazwana zakładka wewnątrz transakcji

Zwykła transakcja działa na zasadzie "wszystko albo nic": wszystko pomiędzy BEGIN a COMMIT albo trafia do bazy razem, albo razem zostaje wyrzucone. Zwykle właśnie o to chodzi, ale czasem przydaje się większa precyzja: "Spróbuj tej porcji zmian, a jeśli coś pójdzie źle, cofnij tylko ją i zachowaj resztę transakcji".

Tym właśnie jest savepoint. Wstawiasz nazwaną zakładkę, wykonujesz jakąś pracę, a potem albo ją zachowujesz (RELEASE), albo przewijasz do zakładki (ROLLBACK TO).

Obciążenie Ady i uznanie Borisa zostają. Błędna aktualizacja dla Nobody została wycofana bez utraty reszty transakcji.

Trzy polecenia

Całe API to trzy instrukcje:

  • SAVEPOINT name: ustawia zakładkę.
  • RELEASE SAVEPOINT name: zachowuje pracę wykonaną od zakładki i usuwa zakładkę.
  • ROLLBACK TO SAVEPOINT name: cofa wszystko od zakładki, a zakładka zostaje na miejscu, więc możesz spróbować ponownie.

Słowo SAVEPOINT po RELEASE i ROLLBACK TO jest opcjonalne: działają zarówno RELEASE risky, jak i ROLLBACK TO risky.

Z punktu widzenia końcowej bazy wiersz próba kroku 2 nigdy nie istniał. Cała reszta zostaje zapisana.

Savepointy bez zewnętrznej transakcji

Mały zwrot akcji: możesz wydać SAVEPOINT bez wcześniejszego BEGIN. SQLite po cichu otwiera za ciebie transakcję, a najbardziej zewnętrzny savepoint pełni rolę samej transakcji. RELEASE na tym savepoincie zatwierdza zmiany, a ROLLBACK TO przewija bez zatwierdzania.

Dlatego savepointy są czasem opisywane jako "nazwane transakcje". Jednak mieszanie obu stylów w prawdziwym kodzie wprowadza zamieszanie, więc wybierz jeden. Większość osób używa jawnego BEGIN ... COMMIT jako zewnętrznej granicy, a savepointów tylko jako wewnętrznych punktów częściowego cofania.

Zagnieżdżanie savepointów

Savepointy układają się w stos. Możesz ustawić jeden wewnątrz drugiego i wycofać wewnętrzny, nie ruszając zewnętrznego:

Końcowa zawartość: a, b, d. Wycofanie do inner usunęło c, ale praca wykonana przed inner (wstawienie b) została nietknięta, a transakcja trwała dalej.

Wycofanie do zewnętrznego savepointu odrzuca też wszystko, co zrobiono na wewnętrznych poziomach: cały stos powyżej tej nazwy zwija się naraz:

Zarówno b, jak i c zniknęły. ROLLBACK TO outer przewija wszystko od momentu ustawienia outer, łącznie z inner i wstawieniem c.

Po co używać savepointów?

Klasyczny przypadek to przetwarzanie porcji danych, w której pojedyncze elementy mogą się nie udać bez odrzucania całej porcji. Opakuj każdy element w savepoint, a jeśli coś się nie uda, wycofaj się do savepointu i idź dalej:

W prawdziwym kodzie aplikacji błędne wstawienie zgłasza błąd, a aplikacja go przechwytuje, wydaje ROLLBACK TO i kontynuuje. Dwa poprawne wiersze trafiają do bazy, a błędny nie psuje całej porcji.

W ten sam sposób ORM i narzędzia do migracji realizują zagnieżdżone transakcje: tak naprawdę nie zagnieżdżają bloków BEGIN (SQLite na to nie pozwala), tylko mapują zagnieżdżone wywołania na savepointy.

Na co uważać

Kilka szczegółów, na których potykają się osoby, które dopiero poznają savepointy:

  • COMMIT zawsze zatwierdza całą transakcję. Nie ma znaczenia, ile savepointów jest otwartych: COMMIT (lub jego alias END) zamyka całą zewnętrzną transakcję. Nie traktuj RELEASE jak częściowego zatwierdzenia: nic nie jest trwałe, dopóki otaczająca transakcja nie zostanie zatwierdzona.
  • ROLLBACK (bez TO) przerywa wszystko. Kończy transakcję i odrzuca wszystkie otwarte savepointy. Używaj ROLLBACK TO name, gdy chcesz, by transakcja trwała dalej.
  • Savepoint pozostaje otwarty, dopóki nie zostanie zwolniony albo wycofany. Zapomniane RELEASE nie powoduje utraty danych, ale zakładka po prostu czeka do końca transakcji.
  • Nazwy nie muszą być unikalne. Jeśli ustawisz SAVEPOINT s dwa razy, ROLLBACK TO s znajdzie najnowszy. Przydatne przy rekurencji, mylące, jeśli zdarzy się przypadkiem.

Dalej: widoki

Savepointy dają większą kontrolę nad zapisami. Kolejny krok to kształtowanie tego, jak czytasz: zapisanie zapytania jako nazwanego obiektu wielokrotnego użytku, z którego możesz robić SELECT jak z tabeli. To widok i o nim za chwilę.

Najczęściej zadawane pytania

Czym jest savepoint w SQLite?

Savepoint to nazwany znacznik, który ustawiasz wewnątrz transakcji. Później możesz zrobić ROLLBACK TO do tej nazwy, by cofnąć wszystko, co zrobiono po nim, albo RELEASE, by zachować zmiany i usunąć znacznik. Savepointy pozwalają traktować części transakcji jako mniejsze jednostki, które da się odzyskać.

Czym różni się savepoint od transakcji w SQLite?

Transakcja zaczyna się od BEGIN i kończy przez COMMIT lub ROLLBACK. Savepoint ustawia się wewnątrz transakcji przez SAVEPOINT name i daje punkt częściowego cofnięcia. Wycofanie do savepointu nie kończy otaczającej transakcji: możesz dalej pracować i zatwierdzić ją później.

Czy savepointy w SQLite można zagnieżdżać?

Tak. Możesz układać savepointy o różnych nazwach jeden na drugim, a ROLLBACK TO outer cofa wszystko aż do tego poziomu, łącznie z wewnętrznymi savepointami. Nazwy nie muszą być unikalne: SQLite używa najnowszego savepointu o danej nazwie, czyli standardowego zachowania stosu.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ