Ecco il mio problema:Strano comportamento con @Transactional (propagazione = Propagation.REQUIRES_NEW)
Sono in esecuzione di un lotto su un'applicazione Java EE/Primavera/Hibernate. Questo batch chiama uno method1
. Questo metodo chiama uno method2
che può generare UserException
(una classe che si estende RuntimeException
). Ecco come sembra:
@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) {
// ...
}
// ...
}
}
L'eccezione viene catturato come l'esecuzione continua, ma alla fine del method1
quando la transazione è chiusa una RollbackException è gettato.
Ecco la traccia dello stack:
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)
Quando method2
non sta gettando questa eccezione, funziona bene.
Quello che ho cercato:
- Impostazione
@Transactional(noRollbackFor={UserException.class}))
sumethod1
- cercare di prendere in
method2
Ma non ha cambiato nulla.
Poiché l'eccezione viene generata in una transazione diversa in cui si è verificato un rollback, non capisco perché non funzioni. Ho dato un'occhiata a questo: Jpa transaction javax.persistence.RollbackException: Transaction marked as rollbackOnly ma non mi è stato di grande aiuto.
Sarò molto grato se qualcuno potrebbe darmi un indizio.
Aggiornamento
Ho fatto il lavoro impostando propagation=Propagation.REQUIRES_NEW
sul metodo chiamato da method2
(che è in realtà quello che sta inviando l'eccezione). Questo metodo è definito in una classe molto simile al mio BatchService
. Quindi non vedo perché funzioni su questo livello e non su method2
.
- Ho impostato
method2
come pubblico come l'annotazione@Transactional
non viene presa in considerazione se il metodo è privato, come ha detto nella documentazione:
L'annotazione @Transactional può essere posta prima di un interfaccia definizione, un metodo su un'interfaccia, una definizione di classe o un metodo pubblico su una classe.
- Ho anche provato ad usare
Exception
invece diRuntimeException
(come è più appropriato) ma anche non ha cambiato nulla.
Anche se funziona la domanda rimane aperta in quanto ha uno strano comportamento e mi piacerebbe capire perché non si comporta come dovrebbe essere.
Vedere http://stackoverflow.com/questions/5152686/self-injection-with-spring/ per possibili soluzioni alternative. – Vadzim