Oto mój problem:Dziwne zachowanie z @Transactional (propagacja = Propagation.REQUIRES_NEW)
biegnę partię na aplikacji Java EE/wiosna/hibernacji. Ta partia wywołuje numer method1
. Ta metoda wywołuje method2
, która może rzucić UserException
(klasa rozszerzająca RuntimeException
). Oto jak to wygląda:
@Transactional
public class BatchService implements IBatchService {
@Transactional(propagation=Propagation.REQUIRES_NEW)
public User method2(User user) {
// Processing, which can throw a RuntimeException
}
public void method1() {
// ...
try {
this.method2(user);
} catch (UserException e) {
// ...
}
// ...
}
}
Wyjątkiem jest przechwycony jako realizacja trwa, ale na koniec method1
kiedy transakcja zostanie zamknięta na RollbackException jest wyrzucane.
Oto ślad stosu:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy128.method1(Unknown Source)
at batch.BatchController.method1(BatchController.java:202)
Kiedy method2
nie rzuca ten wyjątek, to działa dobrze.
Co próbowałem:
- Ustawianie
@Transactional(noRollbackFor={UserException.class}))
namethod1
- spróbować połowu w
method2
Ale to niczego nie zmieni.
Ponieważ wyjątek jest zgłaszany w innej transakcji, w której nastąpiło wycofanie, nie rozumiem, dlaczego nie działa. Spojrzałem na to: Jpa transaction javax.persistence.RollbackException: Transaction marked as rollbackOnly, ale tak naprawdę nie pomogło mi to.
Będę bardzo wdzięczny, jeśli ktoś da mi wskazówkę.
Aktualizacja
Zrobiłem to działa poprzez ustawienie propagation=Propagation.REQUIRES_NEW
na metodzie zwanej przez method2
(co jest rzeczywiście taki, który wysyła wyjątek). Ta metoda jest zdefiniowana w klasie bardzo podobnej do mojej BatchService
. Więc nie rozumiem, dlaczego działa na tym poziomie, a nie na method2
.
- mam ustawione
method2
jako publiczny jako adnotacja@Transactional
nie jest brany pod uwagę, jeśli metoda jest prywatny jak powiedział w dokumentacji:
@Transactional adnotacja może być umieszczony zanim interfejs definicja, metoda na interfejsie, definicja klasy lub publiczna metoda na klasie.
- Próbowałem również użyć
Exception
zamiastRuntimeException
(jak to jest bardziej odpowiednie), ale to też nic nie zmieni.
Nawet jeśli działa, pytanie pozostaje otwarte, ponieważ ma dziwne zachowanie i chciałbym zrozumieć, dlaczego nie zachowuje się tak, jak powinno być.
Zobacz http://stackoverflow.com/questions/5152686/self-injection-with-spring/ dla możliwych obejść. – Vadzim