Chcę wiedzieć, co się właściwie dzieje, kiedy adnotujesz metodę @Transactional
? Oczywiście wiem, że Spring zawinie tę metodę w Transakcji.
Ale mam następujące wątpliwości:
- Słyszałem, że Spring tworzy klasę proxy ? Czy ktoś może wyjaśnić to bardziej szczegółowo . Co faktycznie znajduje się w tej klasie proxy? Co stanie się z rzeczywistą klasą? I jak mogę zobaczyć klasę proxy stworzoną przez Springa
- Przeczytałem również w dokumentach wiosennych, że:
Uwaga: Ponieważ ten mechanizm jest oparty na serwerach proxy, przechwytywane będą tylko zewnętrzne wywołania metod przychodzące przez serwer proxy . Oznacza to, że „samodzielne wywołanie”, tj. Metoda w obiekcie docelowym wywołująca inną metodę obiektu docelowego, nie doprowadzi do faktycznej transakcji w czasie wykonywania, nawet jeśli wywoływana metoda jest oznaczona
@Transactional
!
Źródło: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Dlaczego tylko zewnętrzne wywołania metod będą podlegać Transakcji, a nie metody samodzielnego wywoływania?
Odpowiedzi:
To jest duży temat. Dokument źródłowy z wiosny poświęca mu wiele rozdziałów. Polecam przeczytać te dotyczące programowania i transakcji zorientowanych na aspekty , ponieważ deklaratywne wsparcie transakcji Spring wykorzystuje AOP u podstawy.
Ale na bardzo wysokim poziomie Spring tworzy proxy dla klas, które deklarują @Transactional na samej klasie lub na elementach. Serwer proxy jest w większości niewidoczny w czasie wykonywania. Zapewnia Springowi wstrzykiwanie zachowań przed wywołaniami metod, w ich pobliżu lub w ich pobliżu. Zarządzanie transakcjami jest tylko jednym z przykładów zachowań, które można zaczepić. Kolejne są kontrole bezpieczeństwa. Możesz także podać własne, np. Rejestrowanie. Kiedy więc adnotujesz metodę za pomocą @Transactional , Spring dynamicznie tworzy proxy, które implementuje ten sam interfejs (interfejsy) co klasa, którą adnotujesz. A kiedy klienci wykonują wywołania w twoim obiekcie, połączenia są przechwytywane, a zachowania wprowadzane za pośrednictwem mechanizmu proxy.
Nawiasem mówiąc, transakcje w EJB działają podobnie.
Jak zauważyłeś, mechanizm proxy działa tylko wtedy, gdy przychodzą połączenia z jakiegoś obiektu zewnętrznego. Kiedy wykonujesz wywołanie wewnętrzne w obiekcie, tak naprawdę wykonujesz wywołanie poprzez odwołanie „ to ”, które omija proxy. Istnieją jednak sposoby obejścia tego problemu. Wyjaśniam jedno podejście w tym poście na forum, w którym używam BeanFactoryPostProcessor do wstrzykiwania instancji proxy do klas „samo-referencyjnych” w czasie wykonywania. Zapisuję to odwołanie w zmiennej składowej o nazwie „ ja ”. Następnie, jeśli muszę wykonywać połączenia wewnętrzne, które wymagają zmiany statusu transakcji wątku, kieruję połączenie przez serwer proxy (np. „ Me.someMethod ()".) Wpis na forum wyjaśnia bardziej szczegółowo. Zauważ, że kod BeanFactoryPostProcessor byłby teraz trochę inny, ponieważ został napisany w ramce czasowej Spring 1.x. Mam jednak nadzieję, że daje to pomysł. Mam zaktualizowaną wersję, która Prawdopodobnie mógłbym udostępnić.
źródło
BeanFactoryPostProcessor
. Istnieje jednak (moim zdaniem) bardzo podobna metoda opisana w tej odpowiedzi: stackoverflow.com/a/11277899/3667003 ... a także inne rozwiązania w całym wątku.Gdy Spring załaduje definicje komponentu bean i zostanie skonfigurowany do wyszukiwania
@Transactional
adnotacji, utworzy te obiekty proxy wokół faktycznego komponentu bean . Te obiekty proxy są instancjami klas generowanych automatycznie w czasie wykonywania. Domyślne zachowanie tych obiektów proxy podczas wywoływania metody polega na wywołaniu tej samej metody na fasoli „docelowej” (tj. Fasoli).Jednak proxy mogą być również dostarczane z przechwytywaczami, a gdy są obecne, przechwyty te zostaną wywołane przez proxy, zanim wywoła metodę fasoli docelowej. W przypadku ziaren docelowych opatrzonych adnotacjami
@Transactional
Spring utworzy obiektTransactionInterceptor
i przekaże go do wygenerowanego obiektu proxy. Więc kiedy wywołujesz metodę z kodu klienta, wywołujesz metodę na obiekcie proxy, który najpierw wywołujeTransactionInterceptor
(która rozpoczyna transakcję), która z kolei wywołuje metodę na fasoli docelowej. Po zakończeniu wywołaniaTransactionInterceptor
zatwierdza / wycofuje transakcję. Jest przezroczysty dla kodu klienta.Jeśli chodzi o „metodę zewnętrzną”, jeśli twoja fasola wywoła jedną ze swoich własnych metod, nie zrobi tego za pośrednictwem proxy. Pamiętaj, że Spring otacza twoją fasolę proxy, twoja fasola nie ma o niej wiedzy. Tylko połączenia z „zewnątrz” Twojej fasoli przechodzą przez serwer proxy.
To pomaga?
źródło
Jako osoba wizualna lubię ważyć schemat sekwencji wzoru proxy. Jeśli nie wiesz, jak czytać strzały, czytam pierwszą w ten sposób:
Client
wykonujeProxy.method()
.(Mogłem opublikować zdjęcie pod warunkiem, że wspomniałem o jego pochodzeniu. Autor: Noel Vaes, strona internetowa: www.noelvaes.eu)
źródło
Najprostsza odpowiedź to:
Niezależnie od metody zadeklarujesz
@Transactional
granicę rozpoczęcia i zakończenia transakcji po jej zakończeniu.Jeśli używasz wywołania JPA, wszystkie zatwierdzenia są w tej granicy transakcji .
Powiedzmy, że oszczędzasz byt1, byt2 i byt3. Teraz podczas zapisywania entity3 wyjątek występuje , a następnie jako enitiy1 i entity2 jest w tej samej transakcji tak entity1 i entity2 będzie wycofywania z entity3.
Transakcja :
Jakikolwiek wyjątek spowoduje wycofanie wszystkich transakcji JPA z DB. Wewnętrznie transakcje JPA są używane przez Spring.
źródło
Może być późno, ale natknąłem się na coś, co wyjaśnia twoje obawy związane z proxy (ładnie przechwycone będą tylko wywołania metod „zewnętrznych” przychodzące przez proxy).
Na przykład masz klasę, która wygląda tak
i masz aspekt, który wygląda następująco:
Kiedy wykonasz to w ten sposób:
}
Wyniki wywołania kickOff powyżej podanego powyżej kodu.
ale kiedy zmienisz kod na
Widzisz, metoda wewnętrznie wywołuje inną metodę, więc nie zostanie przechwycona, a wynik będzie wyglądał następująco:
Możesz to ominąć, robiąc to
Fragmenty kodu pobrane z: https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/
źródło
Wszystkie istniejące odpowiedzi są poprawne, ale nie mogę podać tylko tego złożonego tematu.
W celu uzyskania kompleksowego, praktycznego wyjaśnienia możesz zajrzeć do przewodnika Spring @Transactional Dogłębny , który stara się objąć zarządzanie transakcjami w ~ 4000 prostych słowach, z dużą ilością przykładów kodu.
źródło