1
votes

I have a problem with a caught RuntimeException marked as @ApplicationException(rollback=true) rolling back my database transaction and killing the transaction for the following actions.

@ApplicationException(rollback = true)
public class XyzValidationException extends RuntimeException {
   ...
}

The process is a batch import process, which is importing mass data in chunks. When the transction is rolled back, the whole chunk is rolled back and after that selected for import again, so the whole thing repeats in an endless loop.

The applicationserver is a JBoss 7.1 and the database is an Oracle 11.2.

I want to catch the exception, mark the import source entity as faulty, log something, and carry on with the rest of the data.

But catching the exception doesn't prevent the transaction from being rolled back. I have read about it now and understood this behavior is normal. But the thing is, how do you do it then? How do you configure the exception to not roll back when it's caught, and to still do a rollback, when it's uncaught? I could set the exceptions' annotation to @ApplicationException(rollback=false), but then i would prevent a rollback in a situation, where the exception is thrown an not caught, right? In other processes, a Rollback could be sensible, when this exception is thrown. There, I would just not want to catch ist. Does anyone have an idea, how I could achieve this?

I have tried already to change the exception to a checked exception (... extends Exception) and left the annotation with rollback=true. It didnt change the behavior (I was thinkig/hoping that the rollback=true would maybe just take effect on an uncaught exception, and do the trick in my case... but no) Then I tried the checked exception with rollback=false, and as expected, it did the trick. But as described already, I don't want to deactivate the rollback completely... only when the exception is caught. And, if possible, I'd like to stick to the RuntimeException, as we have this 'Policy' to use RuntimeExceptions wherever possible, and the necessary throws-declarations would spread across the application...

Thanks in advance...

Frank

1
When a EJB throws a system exception or an aplication exception with rollback set to true always rollsback the transaction no matter if the exception is caught or not, because the client that catches (or not) the exception is out of the scope of the transaction. The behaviour of the EJB cannot depend of where the client catches or not their exceptions. To change the behaviour you would need to do it inside the ejb method or with an interceptor - areus
Thanks @areus for your comment... You wrote "to change the behaviour you would need to do it inside the ejb method..." - You mean to catch it in the same method where it's thrown? - Frank
Yes. But if you cannot modify the code of the ejb method you could apply an Interceptor - areus

1 Answers

0
votes

You have different ways how to manage this problem.

  1. Use application exceptions. By default, all checked exceptions are application exception (except the RemoteException). In the CMT model, such kinds of exceptions don't cause an automatic rollback. Thus, you can handle occurred exception during processing a chunk and do something staff like log smth without rollback. For rest cases, should use unchecked exceptions which cause an automatic rollback.
  2. If you have some "policy" sticking to unchecked exceptions in your code. You can declare runtime exception like XyzValidationException and annotate it with @ApplicationException(rollback = true), so in the case where it is thrown the transaction won't be rollbacked. For all other code, where there is necessary to make rollback you can use RuntimeException (which has rollback = false by default).
  3. Have a look at CDI if it's possible in your project. It provides @Transactional which includes such properties as rollbackOn and dontRollbackOn.