Krystian Brożek
23 września 2019
Jednym z najważniejszych mechanizmów używanych w relacyjnych bazach danych są transakcje. Właściwie wszystko co robimy w bazie danych działa w oparciu o transakcje. Służą one do utrzymania integralności i pozwalają na wykonanie serii poleceń w całości.
Jak działają transakcje
Skoro jesteśmy przy wysyłaniu, to zobaczmy jak mogłoby to w nim działać. Załóżmy, że ktoś w naszym sklepie internetowym dodał do koszyka produkt, wypełnił dane do wysyłki i klika przycisk „Kup”. Nasz system wysyła zatem do bazy kilka zapytań:
- Sprawdzamy, czy osoba o podanych danych istnieje. Jeśli nie, wtedy dodajemy wpis do tabeli klientów.
- Pobieramy identyfikator klienta.
- Dodajemy nowy wiersz z zamówieniem.
- Pobieramy numer zamówienia.
- Następnie dla każdego produktu sprawdzamy dostępną ilość w magazynie i gdy mamy odpowiedni zapas przypisujemy go do zamówienia.
- Przypisujemy zamówienie do pracownika, który ma je spakować i wysłać.
Wyobraź sobie teraz, że wystąpił błąd w trakcie tego procesu. Oto kilka przykładów, co mogłoby pójść nie tak:
- Problem z danymi – w punkcie 5 brakuje produktu (klient zamówił 3 takie same produkty, a mamy w magazynie tylko 1).
- Problem z dodaniem wiersza do tabeli – klient podał dłuższy opis do zamówienia niż możemy dodać do tabeli (pamiętaj, że wiele baz np. MSSQL i Oracle mają z góry określoną maksymalną ilość znaków w komórce).
- Problem techniczny – tabela została zablokowana (np. proces archiwizujący odczytuje dane) lub zabrakło miejsca na dysku (wielokrotnie spotkałem się z tym problemem tworząc różne systemy, czasem na tym samym dysku znajdziesz bazę danych, aplikację i backupy, a te ostatnie potrafią szybko przybierać na wadze).
- Problem z uprawnieniami – brak uprawnień do tabeli (wydaje się mało prawdopodobne, ale przy instalacji systemu na dodatkowym serwerze mogliśmy po prostu tego nie zrobić, przy jakiejś zmianie mogły zostać przypadkowo usunięte lub tworząc coś nowego odczytującego dane np. API dla zewnętrznych aplikacji nie nadaliśmy ich).
Przypatrzymy się opcji, gdy nie możemy sprawdzić stanu magazynowego produktu, bo usunęliśmy go zanim klient zdążył złożyć zamówienie (dodał do koszyka produkty i po kilku tygodniach kliknął kup). Co powinno się stać w takiej sytuacji? Pakując wszystkie 6 punktów w jedną transakcję, gdy wywali się na punkcie 5, to całość zostanie wycofana. To oznacza, że zamówienie nie pojawi się w bazie danych, a strona naszego sklepu zwróci błąd – oczywiście ładnie zaprezentowany użytkownikowi.
Najprościej określić transakcję jako zestaw zapytań, gdzie wykonuje się wszystko albo nic.
Zarządzanie transakcją
Da się również samemu stwierdzić, kiedy transakcja ma zostać wycofana. Zdarzają się sytuacje kiedy błąd sam z siebie nie poleci, więc musimy sami napisać kod, który w określonych warunkach wycofa transakcję. Często korzystam z tej możliwości w pracy. Wiele tworzonych przeze mnie skryptów robi to, co użytkownik musiałby wykliwać przez długi czas, więc pracuję na danych znajdujących się już w bazie. To powoduje wiele sytuacji, w których coś może pójść nie tak. Znając dokładny wynik skryptu mogę zabezpieczyć się przed niepożądanym jego działaniem wycofując transakcję, gdy jakiekolwiek dane się nie zgadzają.
Z transakcji w bazach danych korzystam również testując, czy coś usunie się poprawnie. Tworzę zapytanie usuwające wiersze, odpalam je, ale kończę całą operację wycofując transakcję. Dzięki temu chcąc usunąć 2 wiersze sprawdzam, czy się usuną (nie wystąpi błąd) i czy na pewno usuną się tylko dwa (może być więcej wierszy spełniających warunek).
W bazie MSSQL wygląda to następująco:
1 2 3 4 |
BEGIN TRANSACTION DELETE FROM Pracownicy WHERE Imie = ‘Anna’ AND Nazwisko = ‘Kowalska’ ROLLBACK TRANSACTION |
To spowoduje usunięcie Anny Kowalskiej, a następnie wycofanie całej operacji – czyli pani Ania wciąż będzie w bazie danych.
Zatwierdzenie transakcji odbywa się za pomocą COMMIT TRANSACTION.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
BEGIN TRANSACTION DECLARE @IloscWierszy int = 0 --deklaracja zmiennej INSERT INTO PracownicyArchiwum (Imie, Nazwisko, PESEL) --dodanie wierszy na podstawie wyniku SELECTa SELECT Imie, Nazwisko, PESEL FROM Pracownicy WHERE Imie = 'Anna' AND Nazwisko = 'Kowalska' SELECT @IloscWierszy = @IloscWierszy + @@ROWCOUNT --zwiększenie wartości zmiennej IF @IloscWierszy = 1 BEGIN PRINT 'Dodano poprawną ilość wierszy' COMMIT TRANSACTION --zatwierdzenie transakcji END ELSE BEGIN PRINT 'Wystąpił błąd. Próbowano dodać: ' + CAST(@IloscWierszy as varchar(10)) + ' wierszy' PRINT 'Zmiany zostały wycofane' ROLLBACK TRANSACTION --wycofanie transakcji END |
Przykład dotyczy MSSQLa. W przypadku bazy Oracle mamy SET TRANSACTION jako rozpoczęcie transakcji, a w MySQL START TRANSACTION. Mechanizm działa pozostaje jednak ten sam.
Zmienna @@ROWCOUNT przechowuje informację o ilości wierszy, na których operowała ostatnia instrukcja. Skoro robiliśmy INSERT jednego wiersza, wtedy w tej zmiennej otrzymamy wartość 1. Gdybyśmy zrobili SELECT zwracający 5 wierszy, wtedy w zmiennej @@ROWCOUNT znaleźlibyśmy wartość 5.
Przeczytaj więcej

Zapowiedź webinarów i zmian na blogu
Ostatnio dosyć często powtarzam, że chcę coraz szerzej dzielić się swoją wiedzą. Taki mam plan na 2019 rok i sukcesywnie wdrażam go w życie. Przyszła pora, aby podsumować działania, podzielić się wieściami i poinformować, w jakim kierunku będzie zmierzał ten blog.

Rozmowa rekrutacyjna – naucz się mówić o sobie!
Przychodzisz na rozmowę kwalifikacyjną. Witasz się z osobami rekrutującymi. Siadasz. Pada pierwsze polecenie: "Proszę nam opowiedzieć coś o sobie". Spotkasz je na prawie każdej rozmowie kwalifikacyjnej. W dodatku zadane zostanie najczęściej jako pierwsze przed...

Pierwszy krok w VBA, czyli o pisaniu i uruchamianiu makr
Naukę tworzenia makr najlepiej rozpocząć od włączenia zakładki Deweloper w Excelu. Poniżej opisałem jak to zrobić oraz dorzuciłem kilka przydatnych informacji dla osób, które chcą napisać swój pierwszy skrypt w VBA. Zakładka Deweloper W Excelu zakładka Deweloper jest...
„Najprościej określić transakcję jako zestaw zapytań, gdzie wykonuje się wszystko albo nic.”
Pierwszy raz o tym słyszę, dlatego co teraz napiszę pewnie Cię rozbawi, ale zapytam : czy ten zestaw pytań może wykluczyć wszystko albo nic, a poprzez pytania, warunki i jeszcze coś tam, może doprowadzić do odpowiedzi jaki jest rzeczywisty stan magazynu i zaproponować klientowi mniejszą ilość sztuk.
Tak, można zrobić w taki sposób, aby po sprawdzeniu stanu, użytkownik był informowany o mniejszej ilości. Jednak nie spotkałem się z realizacją takiej funkcjonalności po stronie bazy, tylko po stronie aplikacji/strony