Comportamento estranho com @Transactional (propagation = Propagation.REQUIRES_NEW)
Aqui está o meu problema:
Estou executando um lote em um aplicativo Java EE / Spring / Hibernate. Este lote chama ummethod1
. Este método chama ummethod2
que pode jogarUserException
(uma classe que se estendeRuntimeException
). Aqui está como parece:
@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) {
// ...
}
// ...
}
}
A exceção é capturada à medida que a execução continua, mas no finalmethod1
quando a transação é fechada, uma RollbackException é lançada.
Aqui está o rastreamento de pilha:
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)
Quandomethod2
não está jogando essa exceção, funciona bem.
O que eu tentei:
Configuração@Transactional(noRollbackFor={UserException.class}))
emmethod1
Tente e peguemethod2
Mas isso não mudou nada.
Como a exceção é lançada em uma transação diferente em que ocorreu uma reversão, não entendo por que ela não funciona. Eu dei uma olhada nisso:Transação Jpa javax.persistence.RollbackException: Transação marcada como rollbackOnly mas isso realmente não me ajudou.
Eu ficarei muito grato se alguém puder me dar uma pista.
Atualizar
Eu fiz isso funcionar definindopropagation=Propagation.REQUIRES_NEW
no método chamado pormethod2
(que é realmente aquele que está enviando a exceção). Este método é definido em uma classe muito semelhante à minhaBatchService
. Então eu não vejo porque funciona nesse nível e não emmethod2
.
method2
tão público quanto a anotação@Transactional
não é levado em conta se o método é privado como dito na documentação:A anotação @Transactional pode ser colocada antes de uma definição de interface, um método em uma interface, uma definição de classe ou um método público em uma classe.
Eu também tentei usarException
ao invés deRuntimeException
(como é mais apropriado), mas também não mudou nada.Mesmo que esteja funcionando, a questão permanece em aberto, pois tem um comportamento estranho e eu gostaria de entender por que ela não está agindo como deveria.