Skip to content

7. Zarządzanie równoczesnym dostępem do danych

Do tej pory korzystaliśmy z tabel, których byliśmy jedynymi użytkownikami. W praktyce, na komputerze obsługującym wielu użytkowników, dane są najczęściej współdzielone między różnymi użytkownikami. Powstaje zatem pytanie: kto może korzystać z danej tabeli i w jaki sposób (przeglądanie, wstawianie, usuwanie, dodawanie, ...)?

7.1. Tworzenie użytkowników Firebird

Podczas pracy z programem IB-Expert zalogowaliśmy się jako użytkownik SYSDBA. Informację tę można znaleźć we właściwościach otwartego połączenia o nazwie SGBD:

Po prawej stronie widać, że zalogowanym użytkownikiem jest [SYSDBA]. Nie widać jednak jego hasła [masterkey]. [SYSDBA] jest specjalnym użytkownikiem systemu Firebird: posiada pełne uprawnienia do wszystkich obiektów zarządzanych przez SGBD. Można tworzyć nowych użytkowników za pomocą IBExpert, korzystając z opcji [Tools / User Manager] lub następującej ikony:

Image

Pojawi się okno zarządzania użytkownikami:

Image

Przycisk [Add] umożliwia tworzenie nowych użytkowników:

Image

Utwórzmy zatem następujących użytkowników:

nazwa
hasło
ADMIN1
admin1
ADMIN2
admin2
SELECT1
select1
SELECT2
select2
UPDATE1
aktualizacja1
UPDATE2
update2

7.2. Przyznawanie uprawnień dostępu użytkownikom

Baza danych należy do osoby, która ją utworzyła. Bazy danych, które utworzyliśmy do tej pory, należały do użytkownika [SYSDBA]. Aby zilustrować pojęcie uprawnień, utwórzmy (Database / Create Database) nową bazę danych pod identyfikatorem [ADMIN1, admin1]:

Image

i zapiszmy ją pod aliasem DBACCES (ADMIN1). Korzystanie z aliasów pozwala na nawiązywanie połączeń z tą samą bazą danych przy użyciu różnych identyfikatorów, co ułatwia ich identyfikację w eksploratorze baz danych IBExpert:

Teraz utwórzmy dwie następujące tabele: TA i TB:

Tabela TA

Tabela TB

Tabele te nie są ze sobą powiązane.

Za pomocą programu IB-Expert utworzymy drugie połączenie z bazą danych [DBACCES], tym razem pod nazwą [ADMIN2 / admin2]. W tym celu wykorzystamy opcję [Database / Register Database]:

Przejdźmy do pliku DBACCES (ADMIN2) i otwórzmy edytor SQL (Shift + F12):

Będziemy mieli okazję korzystać z różnych połączeń w tej samej bazie danych [DBACCES]. Dla każdego z nich będziemy mieli edytor SQL. W [1] edytor SQL wskazuje alias podłączonej bazy danych. Skorzystaj z tej informacji, aby dowiedzieć się, w którym edytorze SQL się znajdujesz. Będzie to miało znaczenie, ponieważ będziemy tworzyć połączenia, które nie będą miały takich samych uprawnień dostępu do obiektów bazy danych.

Wyświetlmy zawartość tabeli TA:

Image

Otrzymujemy następujący komunikat o błędzie:

Image

Co to oznacza? Baza danych [DBACCESS] została utworzona przez użytkownika [ADMIN1] i w związku z tym jest jego własnością. Tylko on ma dostęp do różnych obiektów tej bazy. Może on przyznawać uprawnienia dostępu innym użytkownikom za pomocą polecenia SQL GRANT. Polecenie to ma różne składnie. Jedna z nich wygląda następująco:

syntaxe
GRANT uprawnienie1, uprawnienie2, ...| ALL PRIVILEGES
ON table/vue
TO użytkownik1, użytkownik2, ...| PUBLIC
[ WITH GRANT OPTION ]
action
przyznaje uprawnienia dostępu privilègei lub wszystkie uprawnienia (ALL PRIVILEGES) na table lub vue dla użytkowników utilisateuri lub dla wszystkich użytkowników ( PUBLIC ). Klauzula WITH GRANT OPTION umożliwia użytkownikom, którzy otrzymali uprawnienia, przekazywanie ich z kolei innym użytkownikom.

Wśród uprawnień privilègei, które można przyznać, znajdują się następujące:

DELETE
uprawnienie do korzystania z polecenia DELETE w odniesieniu do tabeli lub widoku.
INSERT
uprawnienie do korzystania z polecenia INSERT na tabeli lub widoku
SELECT
uprawnienie do używania polecenia SELECT na tabeli lub widoku
UPDATE
uprawnienie do używania polecenia UPDATE na tabeli lub widoku. Uprawnienie to można ograniczyć do określonych kolumn za pomocą następującej składni: GRANT update (col1, col2, ...) ON tabela/widok TO użytkownik1, użytkownik2, ...| PUBLIC [ WITH GRANT OPTION ]

Przyznajmy użytkownikowi [ADMIN2] uprawnienie SELECT do tabeli TA. Tylko właściciel tabeli może przyznać to uprawnienie, c.a.d. W tym przypadku jest to [ADMIN1]. Przejdźmy do połączenia DBACCES (ADMIN1) i otwórzmy nowy edytor SQL (Shift+F12):

Image

Następnie będziemy przechodzić między edytorami SQL. Aby się w tym wszystkim odnaleźć, można skorzystać z opcji [Windows] w menu:

Image

Powyżej widoczne są dwa edytory SQL, z których każdy jest przypisany do konkretnego użytkownika. Wróćmy do edytora SQL (ADMIN1) i wydajmy następujące polecenie:

Image

Następnie zatwierdźmy je za pomocą COMMIT:

Image

Po wykonaniu tych czynności przejdźmy do edytora użytkownika ADMIN2, aby ponownie wykonać polecenie SELECT, które zakończyło się niepowodzeniem:

Image

Pojawia się następujący komunikat o błędzie:

Image

Użytkownik [ADMIN2] nadal nie ma uprawnień do przeglądania tabeli [TA]. W rzeczywistości wydaje się, że uprawnienia użytkownika są ładowane w momencie logowania. [ADMIN2] miałby zatem nadal te same uprawnienia, co na początku sesji, czyli żadne. Sprawdźmy to. Wylogujmy użytkownika [ADMIN2]:

  • przejdź do jego połączenia
  • poprośmy o wylogowanie, klikając prawym przyciskiem myszy na połączeniu i wybierając opcję [Deconnect from database] lub (Shift + Ctrl + D)

Image

Jeśli pojawi się okienko z prośbą o podanie [COMMIT], wpisz [COMMIT]. Następnie ponownie zalogujmy użytkownika [ADMIN2], wybierając powyższą opcję [Reconnect]. Po wykonaniu tej czynności wróćmy do edytora SQL (ADMIN2) i ponownie uruchommy żądanie SELECT, które zakończyło się niepowodzeniem:

Image

Otrzymujemy wówczas następujący wynik:

Image

Tym razem ADMIN2 może przeglądać tabelę TA dzięki uprawnieniu SELECT, które przyznał mu właściciel ADMIN1. Zazwyczaj jest to jedyne uprawnienie, jakie posiada. Sprawdźmy to. Nadal w edytorze SQL (ADMIN2):

Ekran po prawej stronie pokazuje, że ADMIN2 nie posiada uprawnienia DELETE w tabeli TA.

Wróćmy do edytora SQL (ADMIN1), aby przyznać użytkownikowi ADMIN2 szersze uprawnienia. Kolejno wydajemy dwa następujące polecenia:

  • pierwsze polecenie przyznaje użytkownikowi ADMIN2 wszystkie uprawnienia dostępu do tabeli [TA], a ponadto możliwość przyznawania przez niego samych uprawnień (WITH GRANT OPTION)
  • drugie polecenie zatwierdza poprzednie

Po wykonaniu tej czynności, podobnie jak poprzednio, odświeżmy połączenie użytkownika [ADMIN2] (Rozłącz / Połącz ponownie), a następnie w edytorze SQL (ADMIN2) wpiszmy następujące polecenia:

ADMIN2 usunęło wszystkie wiersze z tabeli TA. Cofnijmy to usunięcie za pomocą polecenia ROLLBACK:

Sprawdźmy, czy ADMIN2 może z kolei nadać uprawnienia do tabeli TA.

Teraz nawiążmy połączenie z bazą danych [DBACCES] (Database / Register database) pod nazwą [SELECT1 / select1], jednym z wcześniej utworzonych użytkowników, a następnie kliknijmy dwukrotnie na utworzony w ten sposób link w [Database Explorer]:

Przejdźmy do tego nowego połączenia i otwórzmy nowy edytor SQL (Shift + F12), aby wprowadzić w nim następujące polecenia:

Użytkownik SELECT1 posiada uprawnienie SELECT w tabeli TA. Czy ma możliwość przekazania tego uprawnienia użytkownikowi SELECT2?

 

Operacja zakończyła się niepowodzeniem, ponieważ użytkownik SELECT1 nie otrzymał uprawnienia do przekazania uprawnienia SELECT, które otrzymał od użytkownika ADMIN2. Aby to było możliwe,użytkownik ADMIN2 użył klauzuli WITH GRANT OPTION w swoim zleceniu SQL GRANT. Zasady przekazywania są proste:

  • użytkownik może przekazać jedynie te uprawnienia, które otrzymał, i nic więcej
  • może je przekazać tylko wtedy, gdy otrzymał je wraz z uprawnieniem [WITH GRANT OPTION]

Przyznane uprawnienie można cofnąć za pomocą polecenia REVOKE:

syntaxe
REVOKE uprawnienie1, uprawnienie2, ...| ALL PRIVILEGES
ON table/vue
FROM użytkownik1, użytkownik2, ...| PUBLIC
action
usuwa uprawnienia dostępu privilègei lub wszystkie uprawnienia (ALL PRIVILEGES) na table lub vue dla użytkowników utilisateuri lub dla wszystkich użytkowników ( PUBLIC ).

Spróbujmy. Wróćmy do edytora SQL pliku ADMIN2, aby cofnąć uprawnienie SELECT, które przyznaliśmy użytkownikowi SELECT1:

Rozłączmy, a następnie ponownie nawiążmy połączenie użytkownika SELECT1. Następnie w edytorze SQL (SELECT1) wyświetlmy zawartość tabeli TA:

Użytkownik SELECT1 rzeczywiście utracił uprawnienie do odczytu tabeli TA. Należy zauważyć, że to ADMIN2 nadał mu to uprawnienie, a ADMIN2 je cofnął. Jeśli ADMIN1 spróbuje mu je odebrać, nie zostanie zgłoszony żaden błąd, ale można następnie zauważyć, że SELECT1 zachował swoje uprawnienie SELECT.

Uprawnienie można przyznać wszystkim, stosując następującą składnię: GRANT uprawnienie(a) ON tabela / widok TO PUBLIC. Przyznajmy zatem wszystkim uprawnienie SELECT do tabeli TA. W tym celu można użyć ADMIN1 lub ADMIN2. Używamy ADMIN2:

Utwórzmy połączenie z bazą danych przy użyciu użytkownika USER1 / user1:

Po zalogowaniu się jako DBACCES (USER1) otwórzmy nowy edytor SQL (Shift + F12) i wpiszmy następujące polecenia:

Użytkownik USER1 posiada uprawnienie SELECT do tabeli TA.

7.3. Transakcje

7.3.1. Poziomy izolacji

Odchodzimy teraz od kwestii uprawnień dostępu do obiektów bazy danych, aby zająć się problemem współbieżnego dostępu do tych obiektów. Dwóch użytkowników posiadających wystarczające uprawnienia dostępu do obiektu bazy danych, na przykład tabeli, chce z niego korzystać w tym samym czasie. Co się wtedy dzieje?

Każdy użytkownik pracuje w ramach transakcji. Transakcja to sekwencja poleceń SQL, która jest wykonywana w sposób „atomowy”:

  • albo wszystkie operacje zakończą się powodzeniem
  • albo jedna z nich zakończy się niepowodzeniem, a wtedy wszystkie poprzednie zostaną cofnięte

Ostatecznie operacje w ramach transakcji albo zostały pomyślnie zastosowane, albo żadna z nich nie została zastosowana. Gdy użytkownik sam kontroluje transakcję (co ma miejsce w całym niniejszym dokumencie), zatwierdza ją za pomocą polecenia COMMIT lub anuluje za pomocą polecenia ROLLBACK.

Każdy użytkownik pracuje w ramach własnej transakcji. Zazwyczaj rozróżnia się cztery poziomy izolacji między różnymi użytkownikami:

  • Uncommitted Read
  • Committed Read
  • Odczyt powtarzalny
  • Serializable

Odczyt niezapisany

Ten tryb izolacji nazywany jest również „Dirty Read”. Oto przykład tego, co może się wydarzyć w tym trybie:

  1. użytkownik U1 rozpoczyna transakcję na tabeli T
  2. użytkownik U2 rozpoczyna transakcję na tej samej tabeli T
  3. użytkownik U1 modyfikuje wiersze w tabeli T, ale jeszcze ich nie zatwierdza
  4. użytkownik U2 „widzi” te zmiany i podejmuje decyzje na podstawie tego, co widzi
  5. użytkownik anuluje swoją transakcję za pomocą ROLLBACK

Widać, że w punkcie 4 użytkownik U2 podjął decyzję na podstawie danych, które później okażą się nieprawdziwe.

Committed Read

Ten tryb izolacji pozwala uniknąć powyższej pułapki. W tym trybie użytkownik U2 w kroku 4 nie „zobaczy” zmian wprowadzonych przez użytkownika U1 w tabeli T. Zobaczy je dopiero po tym, jak użytkownik U1 zakończy swoją transakcję.

W tym trybie, zwanym również „Unrepeatable Read”, mogą wystąpić następujące sytuacje:

  1. użytkownik U1 rozpoczyna transakcję na tabeli T
  2. użytkownik U2 rozpoczyna transakcję na tej samej tabeli T
  3. użytkownik U2 tworzy SELECT w celu obliczenia średniej z kolumny C wierszy tabeli T spełniających określony warunek
  4. użytkownik U1 modyfikuje (UPDATE) niektóre wartości w kolumnie C tabeli T i zatwierdza je (COMMIT)
  5. użytkownik U2 ponownie wykonuje tę samą operację SELECT, co w punkcie 3. Zauważy, że średnia w kolumnie C uległa zmianie z powodu modyfikacji wprowadzonych przez U1.

Teraz użytkownik U2 widzi tylko zmiany „zatwierdzone” przez U1. Jednak pozostając w tej samej transakcji, dwie identyczne operacje (3 i 5) dają różne wyniki. Termin „Unrepeatable Read” (odczyt niepowtarzalny) określa tę sytuację. Jest to kłopotliwa sytuacja dla kogoś, kto chce uzyskać stabilny obraz tabeli T.

Repeatable Read

W tym trybie izolacji użytkownik ma gwarancję uzyskania tych samych wyników odczytów z bazy, dopóki pozostaje w tej samej transakcji. Pracuje on na „migawce”, na której nigdy nie są odzwierciedlane zmiany wprowadzone przez inne transakcje, nawet te zatwierdzone. Zmiany te zobaczy dopiero wtedy, gdy sam zakończy swoją transakcję za pomocą polecenia COMMIT lub ROLLBACK.

Ten tryb izolacji nie jest jednak jeszcze idealny. Po wykonaniu operacji 3 opisanej powyżej wiersze przeglądane przez użytkownika U2 są zablokowane. Podczas operacji 4 użytkownik U1 nie będzie mógł modyfikować (UPDATE) wartości w kolumnie C tych wierszy. Może jednak dodawać wiersze (INSERT). Jeśli niektóre z dodanych wierszy spełniają warunek sprawdzany w kroku 3, operacja 5 da średnią inną niż ta uzyskana w kroku 3 z powodu dodanych wierszy.

Aby rozwiązać ten nowy problem, należy przejść do izolacji „Serializable”.

Serializable

W tym trybie izolacji transakcje są całkowicie odizolowane od siebie. Gwarantuje to, że wynik dwóch transakcji przeprowadzanych jednocześnie będzie taki sam, jak gdyby zostały one wykonane jedna po drugiej. Aby to osiągnąć, podczas operacji 4, w której użytkownik U1 chce dodać wiersze, które zmieniłyby wynik operacji SELECT użytkownika U1, zostanie on zablokowany. Pojawi się komunikat o błędzie informujący, że wstawienie nie jest możliwe. Stanie się to możliwe dopiero po zatwierdzeniu transakcji przez użytkownika U2.

Cztery poziomy izolacji transakcji SQL nie są dostępne we wszystkich instancjach SGBD. Firebird udostępnia następujące poziomy izolacji:

  • snapshot: domyślny tryb izolacji. Odpowiada trybowi „Repeatable Read” określonym w standardzie SQL.
  • committed read: odpowiada trybowi „committed read” standardu SQL

Ten poziom izolacji jest ustalany za pomocą polecenia SET TRANSACTION:

syntaxe
SET TRANSACTION
[READ WRITE | READ ONLY]
[WAIT|NOWAIT]
ISOLATION LEVEL [SNAPSHOT | READ COMMITTED]
fonctionnement
podkreślone słowa kluczowe to wartości domyślne
READ WRITE: transakcja może odczytywać i zapisywać
READ ONLY: transakcja może tylko odczytywać
WAIT: w przypadku konfliktu między dwiema transakcjami ta, która nie mogła wykonać swojej operacji, czeka na zatwierdzenie drugiej transakcji. Nie może już wysyłać poleceń SQL.
NOWAIT: transakcja, która nie mogła wykonać swojej operacji, nie jest blokowana. Otrzymuje komunikat o błędzie i może kontynuować pracę.
ISOLATION LEVEL [SNAPSHOT | READ COMMITTED]: poziom izolacji

Spróbujmy. W edytorze SQL (ADMIN1) wpisujemy następujące polecenie SQL:

Image

Widzimy, że polecenie nie zostało zaakceptowane. Nie wiadomo dlaczego...

IB-Expert pozwala ustawić tryb izolacji w inny sposób. Kliknijmy prawym przyciskiem myszy na połączenie DBACCES(ADMIN1), aby wybrać opcję [Database Registration Info]:

Ekran po prawej stronie pokazuje, że dostępna jest opcja [Transactions]. Pozwoli nam ona ustawić poziom izolacji transakcji. Ustawiamy go tutaj na [snapshot]. To samo robimy w przypadku połączenia DBACCES (ADMIN2).

7.3.2. Tryb snapshot

Przyjrzyjmy się poziomowi izolacji snapshot, który jest domyślnym trybem izolacji w Firebirdzie. Gdy użytkownik rozpoczyna transakcję, tworzona jest migawka bazy danych. Użytkownik będzie następnie pracował na tej migawce. W ten sposób każdy użytkownik pracuje na własnej migawce bazy danych. Jeśli wprowadzi do niej zmiany, inni użytkownicy ich nie widzą. Zobaczą je dopiero wtedy, gdy użytkownik, który je wprowadził, zatwierdzi je za pomocą COMMIT.

Można rozważyć dwa przypadki:

  • jeden użytkownik odczytuje tabelę (select), podczas gdy inny ją modyfikuje (insert, update, delete)
  • obaj użytkownicy chcą jednocześnie modyfikować tabelę

7.3.2.1. Zasada spójnego odczytu

Załóżmy, że dwóch użytkowników U1 i U2 pracuje nad tą samą tabelą TAB:

      --------+----------+--------+-------+----------------------
              T1a       T2a      T1b     T2b 

Transakcja użytkownika U1 rozpoczyna się w momencie T1a i kończy się w momencie T1b.

Transakcja użytkownika U2 rozpoczyna się w momencie T2a i kończy się w momencie T2b.

U1 przetwarza zdjęcie TAB wykonane w momencie T1a. W okresie między T1a a T1b wprowadza zmiany w TAB. Inni użytkownicy będą mieli dostęp do tych zmian dopiero w momencie T1b, kiedy to U1 wykona COMMIT.

U2 pracuje nad zdjęciem TAB wykonanym w momencie T2a, a więc to samo zdjęcie, z którego korzystał U1 (o ile inni użytkownicy nie zmodyfikowali w międzyczasie oryginału). Nie „widzi” on zmian, jakie użytkownik U1 mógł wprowadzić w pliku TAB. Będzie mógł je zobaczyć dopiero w momencie T1b.

Zilustrujmy to na przykładzie naszej bazy [DBACCES]. Sprawimy, że obaj użytkownicy, [ADMIN1] i [ADMIN2], będą pracować jednocześnie. Przejdźmy do połączenia DBACCES (ADMIN1) i w edytorze SQL użytkownika ADMIN1 wykonajmy następujące czynności:

ADMIN1 zmodyfikował wiersz nr 2 w tabeli TA, ale nie zatwierdził jeszcze (COMMIT) swojej operacji. Następnie użytkownik ADMIN2 wykonuje operację SELECT na tabeli TA (przechodzimy do edytora SQL z ADMIN2). Znajdujemy się przed momentem T2a z przykładu.

Powrót do edytora SQL z pliku ADMIN1, który zatwierdza dodanie:

 

Powrót do edytora SQL z pliku ADMIN2 w celu ponownego utworzenia pliku SELECT:

ADMIN2 widzi zmiany wprowadzone przez ADMIN1. W trybie migawki transakcja nie widzi zmian wprowadzonych przez inne transakcje, dopóki te ostatnie nie zostaną zakończone.

7.3.2.2. Jednoczesna modyfikacja tego samego obiektu bazy danych przez dwie transakcje

Weźmy przykład z księgowości: U1 i U2 pracują nad kontami. U1 obciąża konto comptex kwotą S i uznaje konto comptey tą samą kwotą. Dokona tego w kilku etapach:

      --------+----------+--------+-------+----------------------
              T1a       T1b     T1c      T1d 

U1 rozpoczyna transakcję w momencie T1a, obciąża konto comptex w momencie T1b, uznaje konto comptey w momencie T1c i zatwierdza obie operacje w momencie T1d. Załóżmy ponadto, że U2 chce wykonać tę samą czynność, rozpoczyna swoją transakcję w momencie T2a i kończy ją w momencie T2d zgodnie z poniższym schematem:

      --------+----------+----+----+-------+------+-----+-------+---------
              T1a       T1b  T2a   T1c     T2b   T1d   T2c    T2d

W momencie T2 wykonano migawkę tabeli kont dla U2. Jest ona spójna zgodnie z zasadą snapshot. U2 widzi stan początkowy kont comptex i comptey, ponieważ U1 nie zatwierdziło jeszcze swoich operacji.

Załóżmy, że comptex ma saldo początkowe w wysokości 1000 € i że każdy z użytkowników U1 oraz U2 chce obciążyć to konto kwotą 100 €.

  • W momencie T1b U1 zmniejsza saldo comptex o 100 €, obniżając je tym samym do 90 €. Operacja ta zostanie zatwierdzona dopiero w momencie T1d.
  • W momencie T2b U2 widzi, że comptex ma 1000 € (zasada spójnego odczytu), zmniejsza jego stan o 100 €, a zatem ustawia go na 90 €.
  • Ostatecznie, w momencie T2d, gdy wszystko zostanie zatwierdzone, saldo konta comptex wyniesie 90 € zamiast oczekiwanych 80 €.

Rozwiązaniem tego problemu jest uniemożliwienie U2 modyfikowania comptex, dopóki U1 nie zakończy swojej transakcji. W ten sposób U2 zostanie zablokowany do momentu T1d. Mechanizm ten zapewnia tryb snapshot.

Zilustrujmy to na przykładzie bazy DBACCES. ADMIN1 rozpoczyna transakcję w swoim edytorze SQL (ADMIN1):

Zaczęliśmy od utworzenia transakcji COMMIT, aby mieć pewność, że rozpoczynamy nową transakcję. Następnie usunęliśmy wiersz nr 4. Transakcja nie została jeszcze zatwierdzona.

Z kolei ADMIN2 rozpoczyna transakcję w edytorze SQL (ADMIN2):

Ekran po prawej stronie pokazuje, że ADMIN2 próbował zmodyfikować wiersz nr 4. Otrzymał komunikat, że nie jest to możliwe, ponieważ ktoś inny już go zmodyfikował, ale jeszcze nie zatwierdził tej zmiany.

Wróćmy do edytora SQL (ADMIN1), aby utworzyć plik COMMIT:

Image

Wróćmy do edytora SQL (ADMIN2), aby ponownie wykonać polecenie UPDATE:

Operacja UPDATE przebiega pomyślnie, mimo że wiersz nr 4 już nie istnieje, co pokazuje następujące po niej polecenie SELECT. W tym momencie polecenie ADMIN2 wykrywa, że wiersz już nie istnieje.

7.3.2.3. Tryb Repeatable Read

Zilustrujmy teraz tryb „Repeatable Read”. Ten poziom izolacji zapewnia tryb „snapshot”. Gwarantuje on, że transakcja zawsze uzyska ten sam wynik podczas odczytu bazy danych.

Zacznijmy od pracy z edytorem SQL pliku ADMIN2:

Przejdźmy teraz do edytora SQL z ADMIN1:

 

Użytkownik ADMIN1 dodał dwa wiersze i zatwierdził swoją transakcję. Wróćmy teraz do edytora SQL (ADMIN2), aby odtworzyć SELECT SUM:

Widać, że ADMIN2 nie uwzględnia dodanych wierszy z pliku ADMIN1, mimo że zostały one zatwierdzone przez plik COMMIT. SELECT SUM daje ten sam wynik, co przed dodaniem wierszy. Na tym polega zasada powtarzalnego odczytu (Repeatable Read).

Teraz, nadal w edytorze SQL (ADMIN2), zatwierdźmy transakcję za pomocą COMMIT, a następnie ponownie uruchommy SELECT i SUM:

Wiersze dodane przez ADMIN1 są teraz uwzględniane.

7.3.3. Tryb Committed Read

Przyjrzyjmy się teraz trybowi „Committed Read”. Ten poziom izolacji jest analogiczny do poziomu snapshot, z wyjątkiem trybu „Repeatable Read”.

Zaczynamy od zmiany poziomu izolacji transakcji dla obu połączeń.

  • odłączamy obu użytkowników ADMIN1 i ADMIN2
  • zmieniamy poziom izolacji ich transakcji

Image

  • ponownie logujemy użytkowników ADMIN1 i ADMIN2

Wróćmy teraz do poprzedniego przykładu ilustrującego „Repeatable Read”, aby pokazać, że nie obserwujemy już tego samego zachowania. Zacznijmy od pracy z edytorem SQL z ADMIN2:

Przejdźmy teraz do edytora SQL z ADMIN1:

 

Użytkownik ADMIN1 dodał dwa wiersze i zatwierdził swoją transakcję. Wróćmy teraz do edytora SQL (ADMIN2), aby ponownie odtworzyć SELECT SUM:

SELECT SUM nie daje takiego samego wyniku jak przed wprowadzeniem zmian przez ADMIN1. Jest to różnica między trybami snapshot a read committed.