I'm using Spring and JPA with HIbernate underneath. When a PersistenceException is thrown, I want to catch it and return the error message so that it is not propagated up to the caller.
@Transactional
public String save(Object bean) {
String error = null;
try {
EntityManager entityManager = getEntityManager();
for (int i = 0, n = entities.size(); i < n; i ++) {
entityManager.merge(entities.get(i));
}
}
catch (PersistenceException e) {
error = e.getMessage();
}
return error;
}
But I get an exception saying that javax.persistence.RollbackException: Transaction marked as rollbackOnly.
I get that the transaction needs to be rolled back after an exception but how do I roll it back when I've catched the exception and do not want to re-throw it?
RollbackException exception is thrown when the transaction has been marked for rollback only or the transaction has been rolled back instead of committed. This is a local exception thrown by methods in the UserTransaction , Transaction , and TransactionManager interfaces.
To rollback a transaction you can use @Transaction annotation. You can either implement it on method level or class level. Class level @Transactional(rollbackFor = Exception.
So if you throw an Exception or a subclass of it, always use the above with the @Transactional annotation to tell Spring to roll back transactions if a checked exception occurs.
By default, the only exceptions that cause a transaction to roll back are the unchecked exceptions (like RuntimeException ).
By using @Transactional if there are any RuntimeExceptions thrown in the method, it will automatically perform the rollback. You don't need to manually do it. You probably shouldn't be catching that exception at all and instead let it pass to a higher level ExceptionHandler that shows some standard error page to the user (not the stack trace). Also your method is marked void but you are returning a String.
You can use Spring's Exception Translation with a custom PersistenceExceptionTranslator
to translate PersistenceException
into something useful.
Oh, btw, you shouldn't use @Transactional
at the DAO level. Transactions should be started at the service level.
It appears that there is no way to roll back a failed transaction managed by Spring ORM. The code shown in the question is a service class. Extracting its persistence routine to a separate DAO class and having the service class handle PersistenceExceptions
did the trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With