5

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?

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Tom Tucker
  • 11,676
  • 22
  • 89
  • 130

4 Answers4

7

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.

Robby Pond
  • 73,164
  • 16
  • 126
  • 119
  • Thanks, void was just a typo, but I still get the RollbackException? – Tom Tucker Feb 22 '11 at 19:50
  • 1
    What about removing the try and catch? IMO there is no reason for you to catch and handle the exception since you can't "fix" it. – Robby Pond Feb 22 '11 at 19:53
  • Actually I'm catching a constraint violation and trying to show a localized error message on the form the user used to submit the data. – Tom Tucker Feb 22 '11 at 20:17
5

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.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
2

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.

Tom Tucker
  • 11,676
  • 22
  • 89
  • 130
0

Use @Transactional(noRollbackFor={PersistenceException.class}) on the method that is throwing the exception.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Michal Bachman
  • 2,661
  • 17
  • 22
  • Actually @TomTucker when the transaction is rolled back the exception will be caught in the caller method with data access exception.In your example if an excpetion is thrown back after the transaction is rolled back the method which calls the save method would be getting it as a data access object exception (DataAccessException) put this block in your caller method and can catch the exception and can parse it and make a business value out of it... – swati Jul 16 '13 at 23:59