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