CodeGym /Kursy /SQL SELF /Przykład użycia transakcji w prawdziwych scenariuszach

Przykład użycia transakcji w prawdziwych scenariuszach

SQL SELF
Poziom 39, Lekcja 3
Dostępny

Czasami transakcje przypominają bohaterów z filmów o superbohaterach. Ratują nasze bazy danych przed katastrofą podczas awarii, błędów czy problemów. Jeśli masz zadanie wymagające wykonania kilku operacji, których nie można rozdzielić, transakcje zapewnią ich wspólne wykonanie. Zobaczmy, jak to działa na przykładzie obsługi płatności.

Obsługa płatności

Wyobraź sobie klasyczną sytuację: masz dwa konta bankowe i chcesz przelać pieniądze z jednego na drugie. To nie jest po prostu operacja "jednym kliknięciem". Musisz upewnić się, że poprawnie pobrałeś środki z jednego konta i dodałeś je na drugie. Każdy błąd może prowadzić do katastrofy: albo oba konta pozostaną nietknięte, albo zaburzysz balans (np. pieniądze znikną lub pojawią się "z powietrza").

Scenariusz: Przelew pieniędzy między kontami

Oto nasz kod. Czytaj go uważnie, jakby to była wiadomość z odległej galaktyki:

-- Zaczynamy transakcję
BEGIN;

-- Krok 1. Odejmujemy pieniądze z konta nadawcy
UPDATE accounts
SET balance = balance - 100
WHERE account_id = 1;

-- Krok 2. Dodajemy pieniądze na konto odbiorcy
UPDATE accounts
SET balance = balance + 100
WHERE account_id = 2;

-- Wszystko poszło dobrze? To zapisujemy zmiany!
COMMIT;

Co tu jest ważne?

  • Jeśli na Kroku 1 lub Kroku 2 coś pójdzie nie tak (np. błąd w zapytaniu, brak środków), transakcja może być cofnięta przez ROLLBACK, a dane zostaną w stanie początkowym.
  • COMMIT gwarantuje, że zmiany zostaną zastosowane tylko jeśli WSZYSTKIE kroki się powiodą.

Dodajemy sprawdzenie salda

A co jeśli nadawca nie ma wystarczająco środków na przelew? Dodajmy sprawdzenie salda, żeby przypadkiem nie "wprowadzić go na minus".

-- Zaczynamy transakcję
BEGIN;

-- Pobieramy aktualne saldo nadawcy
DO $$
DECLARE
    current_balance NUMERIC;
BEGIN
    SELECT balance INTO current_balance FROM accounts WHERE account_id = 1;

    -- Sprawdzamy, czy wystarczy pieniędzy
    IF current_balance >= 100 THEN
        -- Jeśli wystarczy, wykonujemy przelew
        UPDATE accounts
        SET balance = balance - 100
        WHERE account_id = 1;

        UPDATE accounts
        SET balance = balance + 100
        WHERE account_id = 2;

        -- Zatwierdzamy zmiany
        COMMIT;
    ELSE
        -- Jeśli nie wystarczy, cofamy
        ROLLBACK;
        RAISE NOTICE 'Za mało środków na przelew!';
    END IF;
END $$;

Co tu już ciekawsze?

  • Używamy bloku PL/pgSQL z warunkiem IF. Jeśli saldo jest mniejsze niż potrzebna kwota, transakcja zostanie odrzucona i nic się nie zmieni.
  • ROLLBACK cofa zmiany, jeśli zostały rozpoczęte (chociaż w tym przypadku nie ma jeszcze czego cofać, ale to dobry zwyczaj).
Ważne!

Ten wykład jest poświęcony prawdziwym scenariuszom użycia transakcji, więc postanowiłem podać tu przykład z życia wzięty. Zawiera procedurę składowaną i jest napisany z użyciem PL-SQL. Myślę, że masz już wystarczająco doświadczenia, żeby zrozumieć jak to działa. W przyszłości wrócimy do tematu PL-SQL i przerobimy nawet dużo bardziej złożone przykłady.

Masowa aktualizacja danych w transakcji

Tworzenie transakcji przydaje się nie tylko przy przelewach. Załóżmy, że mamy bazę sklepu internetowego, gdzie codziennie dziesiątki zamówień mogą zmieniać status, np. z "w dostawie" na "zakończone". Jak zaktualizować wiele rekordów naraz tak, żeby w razie awarii mieć możliwość cofnięcia zmian? Oczywiście, używając transakcji.

Przeanalizujmy jeszcze jeden scenariusz: aktualizacja statusów zamówień.

Oto przykład:

-- Zaczynamy transakcję
BEGIN;

-- Krok 1. Aktualizujemy zamówienia z przeszłą datą dostawy
UPDATE orders
SET status = 'completed'
WHERE delivery_date < CURRENT_DATE;

-- Krok 2. Informujemy o udanej aktualizacji
RAISE NOTICE 'Wszystkie statusy zamówień zostały zaktualizowane pomyślnie.';

-- Zatwierdzamy zmiany
COMMIT;

A jeśli coś pójdzie nie tak?

Zawsze istnieje ryzyko błędu. Na przykład, przypadkowo zapomnisz dodać warunek WHERE i teraz wszystkie zamówienia zmieniły status na completed. Żeby uniknąć takich sytuacji, ważne jest zakończenie transakcji lub jawne jej cofnięcie.

Przeanalizujmy scenariusz z cofnięciem:

-- Zaczynamy transakcję
BEGIN;

-- Krok 1. Próba aktualizacji zamówień bez warunku (o nie, błąd!)
UPDATE orders
SET status = 'completed';

-- Cofnięcie transakcji z powodu błędu
ROLLBACK;

-- Teraz zamówienia pozostały bez zmian

Dodajemy trochę "elastyczności" z SAVEPOINT

Nie zawsze trzeba cofać całą transakcję. Jeśli twój scenariusz składa się z kilku działań, możesz chcieć cofnąć tylko część. Tu z pomocą przychodzi SAVEPOINT.

Teraz nasz scenariusz wygląda tak: obsługa kilku kroków z możliwością cofnięcia jednego z nich.

Wyobraź sobie, że obsługujesz zamówienie składające się z kilku kroków: zdjęcie towarów z magazynu, aktualizacja statusu zamówienia, wysłanie powiadomienia do klienta. Jeśli powiadomienie nie zostanie wysłane poprawnie, chcesz cofnąć tylko ten krok, ale zachować zmiany w bazie.

-- Zacznij transakcję
BEGIN;

-- Krok 1. Odejmujemy towary z magazynu
UPDATE products
SET stock = stock - 1
WHERE product_id = 101;

-- Zapisujemy punkt przywracania
SAVEPOINT step1;

-- Krok 2. Aktualizujemy status zamówienia
UPDATE orders
SET status = 'shipped'
WHERE order_id = 202;

-- Próba wysłania powiadomienia do klienta
SAVEPOINT step2;
-- Ups, błąd podczas powiadamiania!
ROLLBACK TO SAVEPOINT step2;

-- Decydujemy, że bezpiecznie zakończyć transakcję
COMMIT;

Podsumowanie

Transakcje to nie tylko narzędzie techniczne, to gwarancja spójności twoich danych. Chronią przed "efektem domina", kiedy jeden błąd może zniszczyć cały system. Za każdym razem, gdy wykonujesz kilka powiązanych operacji, zapytaj siebie: "A co jeśli jedna z nich się wywali?" Jeśli odpowiedź brzmi "katastrofa", to czas użyć transakcji. Pamiętaj: lepiej poświęcić kilka minut na napisanie transakcji, niż kilka godzin na odzyskiwanie danych po awarii. Twoi użytkownicy (i twoje nerwy) podziękują ci za to!

2
Zadanie
SQL SELF, poziom 39, lekcja 3
Niedostępne
Masowa aktualizacja statusów zamówień
Masowa aktualizacja statusów zamówień
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION