Posts Tagged transakcje

Zarządzanie transakcjami przez serwer aplikacji

W środowiskach zarządzanych (czyli np w serwerze aplikacyjnym JBoss AS) to te systemu mogą zarządzać transakcjami, czyli rozpoczynać, kończyć je w odpowiednim momencie, zwalniając z tego obowiązku programistę. W aplikacji można zdefiniować, jak dany fragment kodu ma wpływać na transakcje. Jeżeli sposób zachowanie nie zostanie zdefiniowany przez metodę, to kontener rozpoczyna transakcję zanim rozpocznie się wykonywanie metody, i kończy ją tuż przed końcem jej wykonywania. Nie są dozwolone zagnieżdżone transakcje, każda metoda może zostać skojarzona z jedną transakcją.

Definicja rodzaju transakcji

Rodzaje transakcji można zdefiniować przy użyciu adnotacji TransactionAttribute oraz TransactionAttributeType.

Adnotacja TransactionAttribute może występować zarówno na poziomie deklaracji klasy jak i deklaracji metody. Jeżeli zostanie podana przy deklaracji klasy, oznacza to że dany poziom transakcji ma zostać użyty we wszystkich metodach danej klasy, w przypadku deklaracji na poziomie metody odnosi się tylko do niej. W przypadku gdy występuje w jednym jak i drugim miejscu, pod uwagę brana jest wartość występująca przy deklaracji metody.

Poniżej przykład deklarowania rodzajów transakcji, na poziomie klasy i metod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class UserManager {
   
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public String getUserName() {
        return null;
    }
   
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void setUserName(String name) {
       
    }
}

Typy transakcji

Za pomocą adnotacji TransactionAttributeType można zdefiniować rodzaj transakcji, jaka ma obowiązywać w metodach. Występują następujące typy transakcji:

  • MANDATORY
    Konieczność wykonania metody w ramach istniejącej już transakcji. Jeżeli dla danego klienta istnieje już działająca transakcji, dana metoda zostanie w jej ramach wykonana. Jeżeli natomiast taka transakcji nie istnieje, to zostanie wyrzucony wyjątek TransactionRequiredException. Należy użyć tego atrybutu używać wtedy, gdy dana metoda musi zostać wykonana w ramach transakcji klienta.
  • REQUIRED
    Jeżeli klient działa w ramach transakcji i zostanie wywołana metoda oznaczona tym typem, to zostanie ona wykonana w ramach tej transakcji. Jeżeli natomiast klient nie działa w ramach transakcji, to zostanie rozpoczęta nowa, zanim metoda zostanie uruchomiona. Jest to także domyślne zachowanie, jeżeli nie zostanie ustawiony typ transakcji.
  • REQUIRES_NEW
    Jeżeli klient nie działa w ramach transakcji, to po prostu jest rozpoczynana nowa przed uruchomieniem metody. Natomiast jeżeli jest istnieje już działająca transakcja, to podejmowane są następujące kroki:

    1. Zawieszenie aktualnie działającej transakcji.
    2. Rozpoczęcie nowej transakcji do wykonania wybranej metody.
    3. Wywołanie i wykonanie metody.
    4. Po zakończeniu działania metody ponowne uruchomienie wcześniej zawieszonej transakcji.

    Typu tego należy używać w sytuacji, gdy istnieje potrzeba wykonywania danej metody zawsze w nowej transakcji.

  • SUPPORTS
    Jeżeli klient działa w ramach transakcji i wywoła daną metodę, to zostanie ona wykonana w ramach tej transakcji. Jeżeli natomiast transakcja nie istnieje, to nie zostanie ona także rozpoczęta przed wykonaniem wybranej metody.
  • NOT_SUPPORTED
    Jeżeli klient działa w ramach transakcji, to zostanie ona zatrzymana na czas wywołania wybranej metody, a po jej wykonaniu ponownie przywrócona. Jeżeli nie ma takiej transakcji, metoda zostanie po prostu wykonana, bez rozpoczynania nowej.

    Należy używać tego typu wtedy, gdy wybrana metoda nie potrzebuje transakcji do działania, a zależy nam na większej wydajności jej wykonywania (transakcje mają negatywny wpływ na szybkość wykonywania metod).

  • NEVER
    Jeżeli klient działa w ramach transakcji i wywoła metodą oznaczoną tym typem, zostanie wyrzucony wyjątek RemoteException. Natomiast jeżeli transakcja nie istnieje, to metoda zostanie wykonana bez rozpoczynania nowej transakcji.

Mała tabela, która podsumowuje powyższe:

Zachowanie kontenera w zależności od typu i stanu transakcji
Nazwa atrybutu Transakcja istnieje Brak transakcji
MANDATORY używa istniejącej wyrzuca wyjątek
REQUIRED używa istniejącej rozpoczyna nową
REQUIRES_NEW zawiesza istniejącą, rozpoczyna nową rozpoczyna nową
SUPPORTS używa istniejącej działa bez
NOT_SUPPORTED zawiesza istniejącą działa bez
NEVER wyrzuca wyjątek działa bez

Źródła

Tags: , , , , ,

Poziom izolacji transakcji w JDBC

Dostępny interfejs dostępu do baz danych w Javie (JDBC) udostępnia kilka różnych poziomów izolacji poszczególnych transakcji. Pozwala na określenie, jak bardzo poszczególne transakcje mają być oddzielone od siebie. Niezależnie od poziomu izolacji transakcji, operacje takie jak wstawianie (INSERT), usuwanie (DELETE) oraz modyfikowanie (UPDATE) rekordów zachowują się zawsze tak samo, jedynie zachowanie operacji pobierającej (SELECT) dane z tabeli może być rożne.

Poziom transakcji jest ustawiany w ramach pojedynczego połączenia z bazą danych. Można go ustawia się go przy użyciu metody Connection.setTransactionIsolation(). Im wyższy poziom izolacji transakcji tym generalnie mniejsza wydajność operacji na bazie danych oraz większe prawdopodobieństwo wystąpienia blokad w dostępie do bazy danych.

Anomalie występujące w transakcjach

Poniżej znajduje się zestawienie anomalii, jakie mogą wystąpić w transakcjach:

Anomalie występujące w transakcjach
Nazwa anomalii Przykład działania anomalii
Dirty Reads

Mamy z nią do czynienia wtedy, gdy następuje w danej transakcji A odczyt zmodyfikowanych w transakcji B danych, a transakcja ta (B) nie została jeszcze zatwierdzona.

Transakcja A rozpoczyna się, i wywołuje:

SELECT * FROM zamowienia

Transakcja B w tym samym czasie wykonuje:

UPDATE zamowienie
SET wartosc_zamowienia=100
WHERE nr_zamowienia=123

Istnieje możliwość, że w transakcji A zostanie odczytana nowa wartość pola wartosc_zamowienia, nawet jeżeli nie zostanie to zapytanie zatwierdzone.

Non-Repeatable Reads

Ze zdarzeniem takim mamy do czynienia wtedy, gdy zapytania A wykonane w różnych momentach jednej transakcji może zwrócić inne wyniki (to samo zapytanie nie daje tego samego rezultatu). Zdarzyć się tak może, gdy w trakcie działania transakcji dane zostaną zmodyfikowane przez inną operacje na bazie danych.

Transakcja A rozpoczyna się, i wywołuje:

SELECT * FROM zamowienia
WHERE nr_zamowienia=123

Transakcja B w tym samym czasie wykonuje:

UPDATE zamowienie
SET wartosc_zamowienia=100
WHERE nr_zamowienia=123;

COMMIT;

Wykonanie ponowne zapytania w transakcji A spowoduje, że zostanie tym razem zwrócony zmodyfikowany rekord.

Phantom Reads

Z taką sytuacją mamy do czynienia wtedy, gdy transakcja A odczytuje dane z bazy danych, w trakcie jej trwanie transakcja B umieści w bazie danych rekord, który spełnia warunki zapytania z transakcji A. Jeżeli teraz w transakcji ponownie zostanie wykonane zapytanie, nowy rekord także zostanie zwrócony, co powoduje niezgodność wyniku działania dwóch zapytań w ramach tej samej transakcji.

Transakcja A odczytuje dane:

SELECT * FROM zamowienia
WHERE nr_zamowienia > 123

Transakcja B wstawia nowy wiersz do tabeli:

INSERT INTO zamowienia
(nr_zamowienia, nazwa)
VALUES ('140', 'Babol złapany');

COMMIT;

Jeżeli teraz w transakcji A ponownie wykonamy zapytanie, to nowy rekord także zostanie pobrany.

Poziomy transakcji

Rozróżniane są następujące poziomy transakcji:

  • TRANSACTION_READ_UNCOMMITTED

    Brak izolacji. Wszelkie zmiany, także te które nie są zatwierdzone jeszcze, są widoczne dla wszystkich zapytań w bazie danych.

  • TRANSACTION_READ_COMMITTED

    Minimalna izolacja, transakcje widzą tylko takie dane, które już są zatwierdzone i zapisane w bazie danych.

  • TRANSACTION_REPEATABLE_READ

    Poziom ten zapewnia powtarzalność odczytu danych. Jeżeli jakiś rekord zostanie odczytany, to nawet jego zatwierdzona modyfikacja w innej transakcji nie zmieni jego wartości przy ponownym odczycie.

  • TRANSACTION_SERIALIZABLE

    Najwyższy poziom transakcji, zwany szeregowym. Zapewnia on najlepszą izolację poszczególnych transakcji, które nie widzą swoich wzajemnych działań i nie wpływają na siebie. W momencie rozpoczęcia transakcji, stan bazy danych jest „zamrażany” i tylko na takim stanie transakcja może działać.

Lista anomalii jakie występują przy określonych typach transakcji, w zależności od sposobu blokowania danych:
Nazwa transakcji Blokada tabeli Blokada wiersza Wydajność
TRANSACTION_READ_UNCOMMITTED Możliwe: dirty reads, non-repeatable reads, phantom reads Możliwe: dirty reads, non-repeatable reads, phantom reads najszybsza
TRANSACTION_READ_COMMITTED Możliwe: non-repeatable reads i phantom reads Możliwe: non-repeatable reads i phantom reads szybka
TRANSACTION_REPEATABLE_READ Ponieważ blokowana jest cała tabela, to phantom reads nie są możliwe Możliwe są phantom reads średnia
TRANSACTION_SERIALIZABLE Brak anomalii Brak anomalii wolna

Źródła

Tags: , , , ,