Here is my problem :
I'm running a batch on a Java EE/Spring/Hibernate application. This batch calls a method1
. This method calls a method2
which can throw UserException
(a class extending RuntimeException
). Here is how it looks like :
@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) {
// ...
}
// ...
}
}
The exception is catched as the execution continues, but at the end of method1
when the transaction is closed a RollbackException is thrown.
Here is the stack trace :
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)
When method2
is not throwing this exception, it works well.
What I have tried:
- Setting
@Transactional(noRollbackFor={UserException.class}))
on method1
- Try and catch in
method2
But it didn't change anything.
As the exception is thrown in a different transaction where a rollback happened I don't understand why it doesn't work. I had a look at this : Jpa transaction javax.persistence.RollbackException: Transaction marked as rollbackOnly but it didn't really help me.
I will be very greatful if someone could give me a clue.
Update
I've made it work by setting propagation=Propagation.REQUIRES_NEW
on the method called by method2
(which is actually the one which is sending the exception). This method is defined in a class very similar to my BatchService
. So I don't see why it works on this level and not on method2
.
- I've set
method2
as public as the annotation @Transactional
is not taken into account if the method is private as said in the documentation :
The @Transactional annotation may be placed before an interface
definition, a method on an interface, a class definition, or a public
method on a class.
- I also tried to use
Exception
instead of RuntimeException
(as it is more appropriate) but it also didn't change anything.
Even if it is working the question remains open as it has a strange behaviour and I would like to understand why it's not acting like it should be.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…