2010-08-06 10 views
67

Jestem nowy w wiosennej transakcji. Niektóre rzeczy, które uważam za naprawdę dziwne, prawdopodobnie zrozumiałem to poprawnie. Chciałem mieć transakcję na poziomie metody i mam metodę wywołującą w tej samej klasie i wygląda na to, że to się nie podoba, musi być wywołana z oddzielnej klasy. Nie rozumiem, jak to jest możliwe. Jeśli ktoś ma pomysł, jak rozwiązać ten problem, byłbym bardzo wdzięczny. Chciałbym użyć tej samej klasy do wywołania metody transakcji z adnotacjami.Wywołanie metody spring @Transaction metodą w ramach tej samej klasy, nie działa?

Oto kod:

public class UserService { 

    @Transactional 
    public boolean addUser(String userName, String password) { 
     try { 
      // call DAO layer and adds to database. 
     } catch (Throwable e) { 
      TransactionAspectSupport.currentTransactionStatus() 
        .setRollbackOnly(); 

     } 
    } 

    public boolean addUsers(List<User> users) { 
     for (User user : users) { 
      addUser(user.getUserName, user.getPassword); 
     } 
    } 
} 

Odpowiedz

70

Jest to ograniczenie z wiosennym AOP. (obiekty dynamiczne i CGLIB)

Jeśli skonfigurujesz Spring do użycia AspectJ do obsługi transakcji, Twój kod będzie działał.

Prostą i prawdopodobnie najlepszą alternatywą jest refaktoryzacja kodu. Na przykład jedna klasa, która obsługuje użytkowników i jedna, która przetwarza każdego użytkownika. Wtedy zadziała domyślna obsługa transakcji za pomocą Spring AOP.

wskazówki konfiguracyjne dla obsługi transakcji z AspectJ

Aby włączyć Wiosna używać AspectJ dla transakcji, należy ustawić tryb AspectJ:

<tx:annotation-driven mode="aspectj"/> 

Jeśli korzystasz ze starszej wiosna w wersji 3.0, musisz również dodać to do konfiguracji Spring:

<bean class="org.springframework.transaction.aspectj 
     .AnnotationTransactionAspect" factory-method="aspectOf"> 
    <property name="transactionManager" ref="transactionManager" /> 
</bean> 
+0

Dziękuję za informację. Na razie refaktoryzowałem kod, ale czy mógłbyś wysłać mi przykład używając AspectJ lub dostarczyć mi kilka pomocnych linków. Z góry dziękuję. Mikrofon. – Mike

+0

W mojej odpowiedzi dodano konfigurację AspectJ specyficzną dla transakcji. Mam nadzieję, że to pomoże. – Espen

+1

Dziękuję Espen za całą pomoc. To działa!! – Mike

42

Problem tutaj jest , że wiosenne serwery proxy AOP nie rozszerzają, ale raczej zawijają twoją instancję usługi, aby przechwytywać połączenia. Powoduje to, że każde wywołanie "tego" z poziomu instancji usługi jest wywoływane bezpośrednio na tej instancji i nie może być przechwycone przez pakujący serwer proxy (proxy nie jest nawet świadomy takiego połączenia). Wspomniano już o jednym rozwiązaniu. Kolejnym dobrym rozwiązaniem byłoby po prostu, aby Spring wstrzyknął instancję usługi do samej usługi, i wywołaj swoją metodę we wstrzykniętej instancji, która będzie serwerem proxy, który obsługuje twoje transakcje. Ale należy pamiętać, że może to mieć złe skutki uboczne też, jeśli fasoli usługa nie jest pojedyncza:

<bean id="userService" class="your.package.UserService"> 
    <property name="self" ref="userService" /> 
    ... 
</bean> 

public class UserService { 
    private UserService self; 

    public void setSelf(UserService self) { 
     this.self = self; 
    } 

    @Transactional 
    public boolean addUser(String userName, String password) { 
     try { 
     // call DAO layer and adds to database. 
     } catch (Throwable e) { 
      TransactionAspectSupport.currentTransactionStatus() 
       .setRollbackOnly(); 

     } 
    } 

    public boolean addUsers(List<User> users) { 
     for (User user : users) { 
      self.addUser(user.getUserName, user.getPassword); 
     } 
    } 
} 
+2

Jeśli zdecydujesz się na tę trasę (czy to dobry projekt, czy nie jest to inna sprawa) i nie korzystasz z wtrysku konstruktora, upewnij się, że widzisz także [ pytanie] (http://stackoverflow.com/questions/5152686/self-injection-with-spring) – Jeshurun

0

Można autowired BeanFactory wewnątrz tej samej klasy i zrobić

getBean(YourClazz.class)

It automatycznie wyznaczy twoją klasę i uwzględni twoją adnotację @Transactional lub inną aop.

+2

Jest to uważane za złą praktykę, nawet wstrzykiwanie fasoli rekursywnie do samej siebie jest lepsze.Za pomocą getBean (clazz) jest napięty sprzężenie i silna zależność od klas aplikacji ApplicationContext w twoim kodzie, a także pobieranie fasoli przez klasę może nie działać w przypadku owijania fasoli (klasa może być zmieniona). –

5

To jest moje rozwiązanie do samodzielnej inwokacji.

private SBMWSBL self; 
@Autowired private ApplicationContext applicationContext; 

@PostConstruct 
public void postContruct(){ 
    self =applicationContext.getBean(SBMWSBL.class); 
}