16. Transakcje

16. Transakcje

Autor: Grzegorz Chuchra

Opublikowano: 5/24/2006, 12:00 AM

Liczba odsłon: 71769

Rozdział ten w całości będzie poświęcony operowaniu na relacyjnych danych oraz niebezpieczeństwu jakie występuje podczas takich operacji. Dowiemy się, jak zapobiegać przypadkom wycieku danych lub błędom podczas operowania na zasobach repozytorium.
Aby nie opowiadać o abstrakcyjnych procesach, podam kilka przykładowych operacji, które mogą zaburzyć spójność całego systemu i doprowadzić do jego błędnego działania. Książkowy przykład zastosowania transakcji to przelew bankowy. Jeśli chcemy zapłacić za zakupy w sklepie, system informatyczny musi dokonać następujących czynności:

  1. sprawdzić, czy stan twojego konta pozwala na dokonanie zakupu
  2. pobrać odpowiednią kwotę z twojego konta
  3. przekazać pobraną sumę i przesłać ją na konto sklepu

Najważniejsze w tym wszystkim jest to, że jeśli któraś z powyższych operacji się nie powiedzie musimy powrócić do stanu sprzed rozpoczęcia operacji.

Innym technicznym przykładem jest proces wstawiania danych. Przypuśćmy, że obsługujemy bazę danych operatora telefonii komórkowej. Robimy rozliczenie miesięczne i podliczanie kosztów dla poszczególnego użytkownika z danego miesiąca. Operacja na tak ogromnym zasobie danych może trwać parę godzin. I w pewnym momencie komputer się zawiesza. Co się dzieje z danymi? Czy dane przeliczone zostały już wstawione? A jak zostały wstawione - czy poprawnie? Oba powyższe przykłady powinny mieć status dwuwartościowy. Albo się w pełni poprawnie wykonały, albo w całości zostają odwołane. Do tego właśnie służy transakcja. Do odwołania wszystkich operacji, na które została nałożona.
Teraz, kiedy troszeczkę wyjaśniłem, czym jest transakcja przejdźmy do formalnego jej zdefiniowania.

Definicja transakcji

Transakcja jest jednostką wykonywania, w której wszystkie polecenia są wykonane poprawnie lub w przeciwnym przypadku nie jest wykonywane żadne z poleceń. Jest to sekwencja operacji wykonywanych jako jedna logiczna jednostka pracy.

Każda z transakcji tworzona jest z zachowaniem pewnych standardowych własności:

Własności transakcji

Atomic – transakcja jest najmniejszą jednostką logiczną. Znaczy to, że jest wykonywana w całości albo w całości jest odwołana

Consistent – transakcja nie zmienia spójności bazy. To znaczy, że jeśli baza była spójna przed wykonaniem transakcji, będzie też spójna po jej ukończeniu.

Isolated – transakcja musi być izolowana, czyli nie może wchodzić w konflikty z innymi transakcjami wykonywanymi na tym samym zbiorze danych

Durable -  transakcja jest trwała, jeżeli gwarantowane jest, że wykonane działania pozostaną kompletne bez względu na to, co się stanie z bazą po poprawnym zakończeniu transakcji. Jeżeli wystąpi awaria zasilania i serwer bazy danych ulegnie awarii, istnieje gwarancja, że transakcja będzie kompletna po ponownym uruchomieniu serwera.

Aby zagwarantować spójność bazy i mieć pewność, że wykonywane operacje zakończą się sukcesem lub porażką, stosowany jest mechanizm blokowania. Blokady są gwarancją tego, że podczas operowania na danych przez jedną transakcję dane nie zostaną zmienione bądź usunięte.

Rozpoczęcie transakcji na SQL Server 2005 można dokonać na trzy sposoby:

Explicite – jawne rozpoczęcie transakcji za pomocą polecenia BEGIN TRANSACTION

Autocommit – automatyczne, operacje na serwerze standardowo podlegają transakcjom. Każde z poleceń jest automatycznie zatwierdzane po poprawnym wykonaniu. Nie ma wtedy potrzeby commitowania transakcji.

Implicit – niejawne, wywoływane przez programy użytkowe działające na bazie danych.

Zakończenie transakcji odbywa się za pomocą poleceń COMMIT lub ROLLBACK. Polecenia COMMIT używamy, gdy wszystkie operacje od rozpoczęcia transakcji powiodły się. W takiej sytuacji możemy zatwierdzić wszystkie zmiany, jakie zostały wprowadzone. Polecenie to dodatkowo zdejmuje wszystkie blokady z tabel, które zostały zablokowane na czas trwania transakcji.

@STRONA@

Komenda ROLLBACK odwołuje transakcję. Polecenie to odwołuje wszystkie modyfikacje jakie zostały dokonane podczas trwania transakcji poprzez przywrócenie stanu danych sprzed transakcji. Polecenie to, podobnie jak COMMIT, również zdejmuje wszystkie blokady z danych, jakie zostały założone na czas transakcji.

Poniżej przedstawiony jest skrypt zmieniający imiona wszystkich Gregory i John na ich polskie odpowiedniki. Samo zapytanie jest już dla wszystkich oczywiste. Nowością jest oczywiście zabezpieczenie go transakcją.

BEGIN TRANSACTION

UPDATE [AdventureWorks].[Person].[Contact]
SET [FirstName] = 'Grzegorz'
WHERE [FirstName] = 'Gregory'

IF @@ERROR <> 0
            BEGIN
                        RAISERROR ('Błąd, operacja nie udana!', 16, -1)
                        ROLLBACK TRANSACTION
            END

UPDATE [AdventureWorks].[Person].[Contact]
SET [FirstName] = 'Jan'
WHERE [FirstName] = 'John'

IF @@ERROR <> 0
            BEGIN
                        RAISERROR ('Błąd, operacja nie udana!', 16, -1)
                        ROLLBACK TRANSACTION
            END

COMMIT TRANSACTION

Pierwszą operacją, jaką robimy, jest otworzenie transakcji. W tym celu pojawia się polecenie BEGIN TRANSACTION. Następnie mamy nasz skrypt przeprowadzający operacje na danych. Potem następuje blok kodu sprawdzający czy operacja się udała. Standardowo zmienna systemowa @@ERROR posiada informacje z numerem ostatniego błędu. Jeśli błąd nie wystąpił, zmienna ta ma wartość zero. Wyrażenie warunkowe IF @@ERROR <> 0 służy do sprawdzania, czy wystąpił błąd. Jeśli wystąpił, wchodzimy do skryptu, który go wypisze (RAISERROR) i odwołujemy całą transakcję. Jeśli wszystko zakończyło się pomyślnie przechodzimy do kolejnej operacji zmiany imienia i znowu sprawdzamy czy wystąpił jakiś nieprzewidziany wypadek.
Ważne, żeby uświadomić sobie fakt, iż zwykła pojedyncza operacja UPDATE, DELTE czy INSERT, taka jak poniżej:

UPDATE [AdventureWorks].[Person].[Contact]
SET [FirstName] = 'Jan'
WHERE [FirstName] = 'John'

nie musi być opatrzona przez nas transakcją, gdyż jest to standardowa operacja Autocommit, która z definicji zabezpieczona jest przez transakcje.
Powracając jednak do wcześniejszych przykładów, należy pamiętać, że jeśli modyfikujemy dane, które są ze sobą wzajemnie powiązane i niepowodzenie przy zmianie jednego zbioru danych wiąże się z dezaktualizacją zmian na innym zbiorze danych, musimy użyć transakcji.
Na tym etapie wystarczy używać standardowego bloku kodu, który widzieliśmy powyżej.

BEGIN TRANSACTION

/*
            BLOK KODU ZMIENIAJĄCY POWIĄZANE ZE SOBĄ DANE
*/

IF @@ERROR <> 0
            BEGIN
                        RAISERROR ('Błąd, operacja nieudana!', 16, -1)
                        ROLLBACK TRANSACTION
            END

COMMIT TRANSACTION

W najnowszej wersji SQL Server 2005 pojawiła się strukturalna pojawia obsługa nie krytycznych wyjątków. Umożliwia to nieco przyjemniejszą pracę z transakcjami. Kod który funkcjonalnie odpowiada temu z pierwszego przykładu wygląda następująco.

BEGIN TRY
            BEGIN TRANSACTION
                        UPDATE [AdventureWorks].[Person].[Contact]
                        SET [FirstName] = 'Grzegorz'
                        WHERE [FirstName] = 'Gregory'
                        UPDATE [AdventureWorks].[Person].[Contact]
                        SET [FirstName] = 'Jan'
                        WHERE [FirstName] = 'John'
            COMMIT
END TRY

BEGIN CATCH TRAN_ABORT
            ROLLBACK
END CATCH

Szablon bloku try-catch wygląda tak.

BEGIN TRY
            BEGIN TRANSACTION
                        /*
                                   KOD WYKONYWANY
                        */
            COMMIT
END TRY

BEGIN CATCH TRAN_ABORT
            ROLLBACK
END CATCH

Podsumowanie

Transakcje są jednym z kluczowych elementów zapewniających spójność i integralność systemów bazodanowych. W dużych systemach informatycznych nie ma mowy o niezabezpieczeniu operacji na danych za pomocą transakcji. Niewielkie systemy, gdzie utrata bądź niewielkie przekłamania w danych nie czynią dużych szkód i nie wpływają na straty finansowe, mogą sobie pozwolić taki komfort. Moim jednak zdaniem niewielki wysiłek jaki należy włożyć w odpowiednie zabezpieczanie spójności za pomocą opisanego mechanizmu jest małym kosztem i warto stosować politykę zabezpieczenia danych.

Jak wykorzystać Copilot w codziennej pracy? Kurs w przedsprzedaży
Jak wykorzystać Copilot w codziennej pracy? Kurs w przedsprzedaży

Wydarzenia