Przetwarzanie transakcyjne Wielodostęp i ochrona przed awariami
Transakcja Logiczna jednostka pracy w SZBD. Program, instrukcja, czy inny ciąg operacji odwołujący się do bd, który powinien być: niepodzielny (atomicity); przeprowadzający bazę danych ze stanu spójnego w spójny (consistency); dający użytkownikom wrażenie indywidualnego dostępu do bazy (independence); gwarantujący trwałość wykonanych operacji (durability). [ACID]
Niepodzielność transakcji Niech transakcja T będzie sekwencją elementarnych operacji I1,I2,...,In. Zdarzenia uniemożliwiające wykonanie całej T: przerwanie przez użytkownika; błąd operacji (np. brak prawa do danych) kolizja z innymi transakcjami (np. blokada i zagłodzenie); awaria pamięci operacyjnej i utrata jej zawartości; awaria pamięci zewnętrznej i utrata jej zawartości. W każdym z tych przypadków transakcja przerwana przez zdarzenie musi być w całości wycofana. Potem ewentualnie powtórzona (wznowiona).
Sterowanie transakcjami w SQL COMMIT - zatwierdza (wypełnia) aktualną transakcję i rozpoczyna kolejną; ROLLBACK - wycofuje aktualną transakcję i rozpoczyna kolejną; BEGIN TRANSACTION (w niektórych systemach) - jawnie rozpoczyna transakcję; Zazwyczaj połączenie z bazą rozpoczyna pierwszą transakcję, a zamknięcie połączenia kończy (COMMIT) ostatnią.
Wypełnianie/wycofywanie transakcji Transakcja może przeprowadzać zmiany na "prywatnych" kopiach danych, które zapisuje do bazy dopiero w momencie wypełnienia; w przypadku wycofania nie zapisuje zmian; System może prowadzić dziennik (LOG), w którym zapisuje zmiany dokonane przez transakcję na każdej jednostce danych (wartość starą i nową). Transakcja dokonuje zapisów w bazie danych. W razie potrzeby wycofania, stare wartości jednostek są odtwarzane na podstawie zapisów z dziennika.
Spójność transakcji System kontroluje, czy transakcja nie narusza zdefiniowanych więzów (klucza, integralności referencyjnej, asercji (?) itp.). W razie ich naruszenia wycofuje transakcję. Użytkownik (lub aplikacja) musi kontrolować pozostałe warunki spójności i to na niego spada odpowiedzialność za ich zachowanie.
Wielodostęp - pogodzenie działań wielu transakcji T=(I1,I2,I3,I4), S=(J1,J2,J3) Harmonogram: I1,I2,J1,I3,J2,J3,I4 Harmonogram sekwencyjny: I1,I2,I3,I4,J1,J2,J3 lub J1,J2,J3, I1,I2,I3,I4 Harmonogram szeregowalny - taki, którego wynik działania jest równoważny pewnemu harmonogramowi sekwencyjnemu.
Schemat problemu szeregowalności Baza danych: zbiór jednostek (A,B,C,...); Jedna operacja: { read | write } A; Harmonogram H (być może niesekwencyjny) transakcji T1,T2,... jest równoważny harmonogramowi sekwencyjnemu Hs, jeżeli: jeżeli Ti czyta w H wartość jednostki A zapisaną przez Tj, to tak samo jest w Hs (Tj: write A < Ti: read A) ; jeżeli Ti (czyta i ) zapisuje w H wartość jednostki A po zapisaniu jej przez Tj, to tak samo jest w Hs (Tj: write A < Ti: write A); jeżeli Ti czyta w H wartość jednostki A przez zapisaniem jej przez Tj, to tak samo jest w Hs (Ti: read A < Tj: write A);
Graf szeregowalności G=(V,E) dla harmonogramu H transakcji {T1,T2,...,Tn} V={T1,T2,...,Tn} (Ti,Tj)E wtedy i tylko wtedy, gdy istnieje jednostka A, taka że: Ti czyta A zanim Tj ją zapisze lub Ti zapisuje A zanim Tj ją przeczyta/zapisze Harmonogram H jest szeregowalny wtedy i tylko wtedy, gdy transakcje {T1,...,Tn} można uporządkować zgodnie z grafem G, tzn. istnieje porządek liniowy transakcji zgodny z porządkiem zadanym przez krawędzie grafu G.
Nieszeregowalność - utracone zmiany 1) T1: read A A=100 2) T2: read A A=100 3) T2: A = A + 20 120 4) T1: A = A * 1,10 110 5) T2: write A(commit) A=120 6) T1: write A (commit) A=110 Niech początkowo A=100. W powyższym harmonogramie na koniec A=110, a powinno być A=130 (T1,T2) lub A=132 (T2,T1). Analiza grafu dla powyższego harmonogramu także wykazuje jego nieszeregowalność.
Nieszeregowalność – „brudne dane” 1) T1: read A A=100 2) T1: A=A+20 120 3) T1: write A A=120 4) T2: read A A=120 5) T2: A=A*1,10 132 6) T2: write A (commit) A=132 7) T1: rollback A=132 Efektem powyższego harmonogramu powinno być wykonanie tylko transakcji T2 (A=110). Błąd pojawił się, ponieważ pozwoliliśmy T2 czytać "brudne" dane utworzone przez transakcję T1 - niewypełnioną.
Nieszeregowalność - niepowtarzalny odczyt 1) T2: read A (suma+=A); suma = 100 2) T1: read A; A = 100 3) T1: A = A - 10; 90 4) T1: write A; A = 90 5) T1: read B; B = 200 6) T1: B = B +10; 210 7) T1: write B; B = 210 8) T2: read B (suma+=B) suma = 310 Transakcja T2 dokonująca bilansu czyta wartości A i B z różnych momentów, czyli jej wynik nie odpowiada bilansowi z żadnego konkretnego momentu czasu. Graf szeregowalności ewidentnie wykazuje tę sytuację. Fantomy to krotki spelniajace warunek selekcji i wstawione do tabeli w “miedzyczasie”. Niepowtarzalny odczyt, to sytuacja, gdy transakcja czyta dwuktrotnie te sama krotke i widzi za kazdym razem inna wartosc.
Kontrola wielodostępu Metody blokad Transakcja przed uzyskaniem dostępu do jednostki musi ją odpowiednio zablokować (do odczytu lub do zapisu). System zwalnia jednostkę dopiero po dokonaniu modyfikacji przez transakcję; ewentualnie później – po upewnieniu się, że transakcja zostanie wypełniona) Metody znaczników czasowych (stempli) Transakcja ma przypisany znacznik czasowy. Zostawia go przy każdej jednostce, do której się odwołuje (czyta lub modyfikuje). System pilnuje, by transakcje odwoływały się do jednostek w porządku chronologicznym zgodnym ze znacznikami.
Metoda blokad Blokada do odczytu (dzielona): RLOCK (SHARED LOCK); Blokada do zapisu (wyłączna): LOCK (EXCLUSIVE LOCK); Transakcja poprzedza operacje na jednostce założeniem odpowiedniej blokady. RLOCK nie zapobiega założeniu takiej samej (RLOCK) blokady przez inne transakcje. LOCK uniemożliwia założenie jakiejkolwiek (RLOCK lub LOCK) blokady przez inną transakcję. Transakcja zwalnia swoją blokadę po zakończeniu operacji.
Metoda blokad - problemy Szeregowalność harmonogramu w metodzie blokad możemy badać na podstawie grafu analogicznego jak graf szeregowalności (traktując LOCK jak write, a RLOCK jak read). Jest to kłopotliwe, bo graf trzeba zmieniać dynamicznie. Anulowanie kaskadowe - jeżeli transakcja T1 zwolniła jednostkę A przez wypełnieniem się, a T2 ją przeczytała i zmodyfikowała B, którą przeczytała T3, to wycofanie T1 powoduje konieczność wycofania T2, to z kolei implikuje wycofanie T3. Problem ten wynika z czytania brudnych danych przez transakcje. W metodzie blokad możliwe jest zakleszczenie (T1 blokuje A i czeka na B, T2 odwrotnie) i zagłodzenie (T1 zawsze jest uprzedzana przy przydziale blokady jednostki przez inną transakcję).
Metoda blokad - protokoły Blokowanie dwufazowe (2PL) - transakcja najpierw zakłada blokady (faza wzrostu), a potem je zwalnia (faza zmniejszania); Jeżeli wszystkie transakcje przestrzegają 2PL, to ich harmonogram jest szeregowalny. Blokowanie ściśle dwufazowe (rigorous i strict 2PL) - j.w. + transakcje zwalniają blokady dopiero w momencie wypełnienia. W ten sposób w bazie nie ma brudnych danych i nie występuje anulowanie kaskadowe. Odmianą tego protokołu jest trzymanie do momentu wypełnienia tylko blokad wyłącznych.
Zakleszczenie i zagłodzenie Zakleszczeniu można zapobiegać: wykluczając transakcję oczekującą na blokadę po określonym czasie; badając przed przydzieleniem blokady, czy nie spowoduje ona zakleszczenia (czy w grafie oczekiwań nie powstanie cykl); okresowo badając graf oczekiwań i usuwając zakleszczenie, gdy zostanie wykryte poprzez wycofanie jednej z biorących w nim udział transakcji. Zagłodzeniu zapobiegamy zwiększając z czasem priorytet transakcji.
Metoda znaczników czasowych Każda transakcja T otrzymuje unikalny znacznik time(T) - zazwyczaj zgodny z momentem uruchomienia transakcji w systemie. Każda jednostka A ma dwa znaczniki: rtime(A) - znacznik ostatniej transakcji, która czytała A; wtime(A) - znacznik ostatniej transakcji, która zapisała A.
Metoda znaczników czasowych -cd. T chce czytać A: jeżeli time(T)>wtime(A), to OK i rtime(T)=max(time(T),rtime(A)); jeżeli time(T)<wtime(A), to wycofujemy T (i ewentualnie uruchamiamy ponownie z większym znacznikiem czasowym); T chce zapisać A: jeżeli time(T)>rtime(A) i time(T)>wtime(A), to T zapisuje A i wtime(A)=time(T); jeżeli time(T)>rtime(A) i time(T)<wtime(A), to pomijamy zapis dokonywany przez T i kontynuujemy; jeżeli time(T)<rtime(A), to wycofujemy T (i ewentualnie uruchamiamy ponownie z większym znacznikiem czasowym);
Metoda znaczników czasowych Gwarantuje szeregowalność harmonogramu (zgodność z harmonogramem sekwencyjnym odpowiadającym znacznikom czasowym); Nie zapobiega anulowaniu kaskadowemu; Istnieje modyfikacja tej metody polegająca na przechowywaniu wielu wersji czasowych jednostki, które mogą czytać transakcje spóźnione (Oracle) i które można tworzyć w porządku niechronologicznym (ale OSTROŻNIE !!!)
Szeregowalność w SQL (SQL99) SET TRANSACTION [READ ONLY | READ WRITE] [ISOLATION LEVEL { READ UNCOMMITED | READ COMMITED | REPEATABLE READ | SERIALIZABLE} Poziom niezależności WLOCK do wypełnienia RLOCK do wypełnienia LOCK na całe tabele do wypełnienia READ UNCOMMITED Nie - read only NIE READ COMMITED TAK REPEATABLE READ SERIALIZABLE
(idTransakcji, idJednostki, staraWartość, nowaWartość) Trwałość danych Dziennik - plik, w którym są zapisywane wszystkie zmiany dokonywane przez transakcje w formacie: (idTransakcji, idJednostki, staraWartość, nowaWartość) Punkt kontrolny (check point) - moment odnotowywany w dzienniku, w którym cała baza jest kopiowana do pamięci zewnętrznej. Dobrze, gdy w tym momencie nie ma żadnej czynnej transakcji i baza jest zapisywana w spójnym stanie. Kopia archiwalna - spójny obraz bazy danych w bezpiecznej pamięci.