@Transactional metoda wywołująca inną metodę bez @Transactional anotation?

89

Widziałem metodę w klasie Service, która została oznaczona jako @Transactional, ale wywoływała również inne metody w tej samej klasie, które nie zostały oznaczone jako @Transactional.

Czy to oznacza, że ​​wywołanie oddzielnych metod powoduje, że aplikacja otwiera oddzielne połączenia z bazą danych lub zawiesza transakcję nadrzędną itp.?

Jakie jest domyślne zachowanie metody bez adnotacji, która jest wywoływana przez inną metodę z @Transactionaladnotacją?

goe
źródło

Odpowiedzi:

117

Po wywołaniu metody bez @Transactionalwewnątrz bloku transakcji transakcja nadrzędna będzie kontynuowana w nowej metodzie. Użyje tego samego połączenia z metody nadrzędnej (z @Transactional) i każdego wyjątku spowodowanego w wywołanej metodzie (bez @Transactionalspowoduje wycofanie transakcji zgodnie z konfiguracją w definicji transakcji.

Jeśli wywołasz metodę z @Transactionaladnotacją z metody w @Transactionalramach tego samego wystąpienia, wywoływane zachowanie transakcyjne metod nie będzie miało żadnego wpływu na transakcję. Ale jeśli wywołasz metodę z definicją transakcji z innej metody z definicją transakcji i znajdują się one w różnych instancjach, to kod w wywołanej metodzie będzie zgodny z definicjami transakcji podanymi w wywołanej metodzie.

Możesz znaleźć więcej informacji w sekcji Deklaratywny zarządzania transakcjami w dokumentacji transakcji wiosny .

Deklaratywny model transakcji Spring wykorzystuje proxy AOP. więc pełnomocnik AOP jest odpowiedzialny za tworzenie transakcji. Serwer proxy AOP będzie aktywny tylko wtedy, gdy metody z instancją są wywoływane spoza instancji.

Arun P Johny
źródło
czy to domyślne zachowanie sprężyny?
idź
Tak. Jest to zachowanie domyślne.
Arun P Johny
2
@Tomasz Yes. Ale należy również wspomnieć, że zmiana propagacji transakcji w metodzie wywoływanej z innej metody @Transactional nie przyniesie żadnego efektu.
Fil
1
@Tomasz, to miałem na myśli mówiąc will follow the transaction definitions given in the called method. Ale jeśli wywołanie pochodzi z tej samej instancji obiektu, nie będzie miało żadnego efektu, ponieważ wywołanie nie będzie propagowane przez proxy aop, które są odpowiedzialne za obsługę transakcji.
Arun P Johny
5
@Filip, To nie jest całkowicie poprawne, jeśli wywołasz metodę z @Transactionaldefinicją z innego obiektu / instancji, to nawet jeśli metoda wywołująca ma inne @Transactionalatrybuty, wywołana metoda będzie postępować zgodnie z własną definicją transakcji.
Arun P Johny
23
  • Czy to oznacza, że ​​wywołanie oddzielnych metod powoduje, że aplikacja otwiera oddzielne połączenia z bazą danych lub zawiesza transakcję nadrzędną itp.?

To zależy od poziomu propagacji . Oto wszystkie możliwe wartości poziomów .

Na przykład, jeśli poziom propagacji jest ZAGNIEŻDŻONY, bieżąca transakcja zostanie „zawieszona” i zostanie utworzona nowa transakcja ( uwaga: faktyczne utworzenie transakcji zagnieżdżonej będzie działać tylko na określonych menedżerach transakcji )

  • Jakie jest domyślne zachowanie metody bez adnotacji, która jest wywoływana przez inną metodę z adnotacją @Transactional?

Domyślny poziom propagacji (to, co nazywasz „zachowaniem”) jest WYMAGANY . W przypadku wywołania metody „wewnętrznej”, która ma przypisaną do niej @Transactionaladnotację (lub przeprowadzonej deklaratywnie za pomocą XML), zostanie ona wykonana w ramach tej samej transakcji , np. „Nic nowego” nie zostanie utworzone.

tolitius
źródło
A co z wywołaniami podrzędnymi NOT_SUPPORTED, które nie mają adnotacji? Czy dziedziczy NOT_Supported, czy też otworzył nową transakcję, ponieważ REQURED jest wartością domyślną? Na przykład: f1.call () {f2 ()} z adnotacją NOT_SUPPORTED dla f1 i non dla f2.
Dave,
8

@Transactional oznacza granicę transakcji (początek / koniec), ale sama transakcja jest powiązana z wątkiem. Po rozpoczęciu transakcji jest ona propagowana przez wywołania metod, aż pierwotna metoda powróci, a transakcja zostanie zatwierdzona / wycofana.

Jeśli wywoływana jest inna metoda, która ma adnotację @Transactional, propagacja zależy od atrybutu propagacji tej adnotacji.

sourcedelica
źródło
Trzy odpowiedzi w pewnym stopniu są ze sobą sprzeczne, nie mając pewności, która z nich jest dokładniejsza.
Eric Wang
1
@EricWang Chciałem tylko udostępnić, że przetestowałem dzisiaj ten scenariusz, a odpowiedź udzielona przez Arun P Johny (z komentarzami) jest najbardziej dokładna w przypadku tego scenariusza wewnętrznych wywołań.
Vinay Vissh
3

Metoda wewnętrzna wpłynie na metodę zewnętrzną, jeśli metoda wewnętrzna nie ma adnotacji @Transactional.

W przypadku, gdy metoda wewnętrzna jest również opatrzona adnotacją @Transactional z REQUIRES_NEW, nastąpi następujące.

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

Metoda wewnętrzna jest opatrzona adnotacją REQUIRES_NEWi zgłasza wyjątek RuntimeException, więc ustawi swoją transakcję na wycofanie, ale NIE WPŁYNIE na transakcję zewnętrzną. Transakcja zewnętrzna jest ZATRZYMYWANA, gdy rozpoczyna się transakcja wewnętrzna, a następnie WZNOWIONA PO zakończeniu transakcji wewnętrznej. Działają niezależnie od siebie, więc transakcja zewnętrzna MOŻE zostać pomyślnie zatwierdzona.

saran3h
źródło
1
Aby wyjaśnić dla początkujących, jestem prawie pewien, że innerMethod () musi znajdować się na innym beanie (aka obiekt Java zarządzany przez Spring) niż externalMethod (). Jeśli oba znajdują się na tym samym ziarnie, nie sądzę, aby innerMethod faktycznie użyła zachowania transakcyjnego zadeklarowanego w adnotacji. Zamiast tego użyje tego, co jest zadeklarowane w deklaracji externalMethod (). Wynika to z tego, jak Spring obsługuje AOP, który jest używany do adnotacji @Transactional ( docs.spring.io/spring/docs/3.0.x/spring-framework-reference/ ... )
johnsimer