I have a dao class (MyDao
) which is marked with @Transactional
annotaion (on class level) with no additional parameters. In this dao class I have a method which in some case needs to throw a checked exception and perform a transaction rollback. Something like this:
@Transactional
public class MyDao {
public void daoMethod() throws MyCheckedException() {
if (somethingWrong) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new MyCheckedException("something wrong");
}
}
This works perfectly fine. However, this dao method is called from a service method, which is also marked as @Transactional:
public class MyService {
@Autowired
private MyDao myDao;
@Transactional
public void serviceMethod() throws MyCheckedException {
myDao.daoMethod();
}
}
The problem is that when daoMethod()
is called from serviceMethod()
and marks the transaction as rollback only, I get an UnexpectedRollbackException
.
Under the hood, Spring creates two transactional interceptors: one for MyDao
and one for MyService
. When daoMethod()
marks the transaction for rollback, the interceptor for MyDao
performs the rollback and returns. But then the stack moves to the interceptor for MyService
, which finds out about the previous rollback, and throws the UnexpectedRollbackException
.
One solution would be to remove the @Transactional
annotation from MyDao. But this is not feasible right now because MyDao
is used at a lot of places and this could cause errors.
Another solution would be to not set the transaction as rollback only in daoMethod()
but rather mark serviceMethod()
to revert the transaction on MyCheckedException
. But I don't like this solution because I have a lot of these "service methods" and I would have to mark all of them explicitly to rollback on that exception. Also everyone who would add a new service method in the future would have to think of this and therefore it creates opportunities for errors.
Is there a way I could keep setting the transaction as rollback only from daoMethod()
and prevent Spring from throwing the UnexpectedRollbackException
? For instance, with some combination of parameters isolation
and propagation
?