Z http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Zespół Spring zaleca, aby opisywać adnotacje tylko do konkretnych klas @Transactional
, w przeciwieństwie do opisywania interfejsów. Z pewnością możesz umieścić @Transactional
adnotację w interfejsie (lub metodzie interfejsu), ale będzie to działać tak, jak byś tego oczekiwał, jeśli używasz serwerów proxy opartych na interfejsie. Fakt, że adnotacje nie są dziedziczone, oznacza, że jeśli używasz serwerów proxy opartych na klasach, ustawienia transakcji nie zostaną rozpoznane przez infrastrukturę proxy opartą na klasach, a obiekt nie zostanie opakowany w transakcyjny serwer proxy (co byłoby zdecydowanie złe ) . Więc proszę, skorzystaj z rady zespołu Spring i dodaj adnotację tylko do konkretnych klas (i metod konkretnych klas) @Transactional
.
Uwaga: ponieważ ten mechanizm jest oparty na proxy, przechwytywane będą tylko „zewnętrzne” wywołania metod przychodzące przez proxy. Oznacza to, że „samo-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łana metoda jest oznaczona @Transactional
!
(Wyróżnienie dodane do pierwszego zdania, inne wyróżnienia z oryginału).
JdkDynamicAopProxy
przegląda wszystkich doradców bean przy każdym wywołaniu metody (zobacz takżeDefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()
), co w przypadku deklaratywnej konfiguracji transakcji obejmujeBeanFactoryTransactionAttributeSourceAdvisor
. Z koleiTransactionAttributeSourcePointcut#matches()
jest wywoływana, która powinna zbierać informacje dotyczące transakcji. Jest przekazywany do klasy docelowej i zawsze może przechodzić przez wszystkie interfejsy implementowane przez tę klasę. Teraz: dlaczego to nie może działać niezawodnie?@Transactional
adnotacji będą miały zastosowanie? Więc chociaż to wszystko możliwe , nie winię Springa. jira.springsource.org/browse/SPR-975Możesz umieścić je w interfejsie, ale pamiętaj, że w niektórych przypadkach transakcje mogą się nie zdarzyć. Zobacz drugą wskazówkę w sekcji 10.5.6 dokumentacji Spring:
Z tego powodu zalecałbym umieszczenie ich na implementacji.
Dla mnie również transakcje wydają się szczegółem implementacji, więc powinny znajdować się w klasie implementacji. Wyobraź sobie, że masz implementacje opakowujące do rejestrowania lub testowania implementacji (makiety), które nie muszą być transakcyjne.
źródło
Spring zaleca , aby zamiast interfejsu dodawać adnotacje do konkretnych implementacji. Używanie adnotacji w interfejsie nie jest błędne, po prostu można niewłaściwie użyć tej funkcji i nieumyślnie ominąć deklarację @Transaction.
Jeśli zaznaczyłeś coś transakcyjnego w interfejsie, a następnie na wiosnę odwołałeś się do jednej z jej klas implementujących w innym miejscu, nie jest do końca oczywiste, że obiekt, który tworzy spring, nie będzie uwzględniał adnotacji @Transactional.
W praktyce wygląda to mniej więcej tak:
public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} }
źródło
Wspieranie @Transactional na konkretnych klasach:
Generalnie wolę projektować rozwiązanie w trzech sekcjach: API, implementacja i sieć (w razie potrzeby). Staram się, aby API było jak najlżejsze / proste / POJO, minimalizując zależności. Jest to szczególnie ważne, jeśli grasz w rozproszonym / zintegrowanym środowisku, w którym musisz dużo udostępniać interfejsy API.
Umieszczenie @Transactional wymaga bibliotek Spring w sekcji API, co nie jest skuteczne. Dlatego wolę dodać to w implementacji, w której przebiega transakcja.
źródło
Umieszczenie go na interfejsie jest w porządku, o ile wszyscy przewidywalni implementatorzy twojego IFC dbają o dane TX (transakcje nie są problemami, którymi zajmują się tylko bazy danych). Jeśli metoda nie dba o TX (ale musisz ją tam umieścić dla Hibernacji lub czegokolwiek), umieść ją na impl.
Ponadto może być nieco lepiej umieścić
@Transactional
metody w interfejsie:public interface FooService { @Transactional(readOnly = true) void doSmth(); }
źródło