I have a simple question that does not seem to have a simple answer since I hear different things from different people. Simply put, I would like to know what steps need to be taken in rolling back a transaction. I believe that any subclass of RuntimeException, most notably EJBException, triggers a rollback, but what does that mean exactly? Does throwing the exception by itself cause the rollback? Or does one have to explicitly call setRollbackOnly() on the SessionContext? And if the latter is the case, what is the point then of CMT? If I have to write transactional code anyway, I could just as easily write it in BMT, couldn't I?
Any guidance is appreciated. Thanks.
It's confusing because the spec doesn't really say anything very definitive about it. Here's what I know about it:
1. You do NOT have to call setRollbackOnly. As you said, that would be almost equivalent to BMT.
2. I'm not sure that just any RuntimeException will force rollback. We always throw an EJBException (or subclass thereof).
3. What you get back to the caller depends on your interface and whether the caller is already in a transaction. You may get the original EJBException or a TransactionRolledbackException.
4. I believe the rollback is triggered in the EJB stub class at the end of the method. However, it gets more complicated when one EJB calls another. I believe it happens in the stub of the exception-throwing EJB itself.
For what it's worth, what we've found to be a good paradigm is: we define a system-wide exception BaseException that's a subclass of EJBException. Virtually all of our EJB calls use local interfaces. When a piece of code has a problem, it throws a BaseException (or a subclass). In general, none of our code ever catches general Exceptions - they bubble up to the top-level user interface manager, which is built on top of Apache Turbine. The user interface manager then decodes the actual exception that was thrown and displays an error message to the user.
It has made exception handling much simpler; primarily because lack of it, but also because we don't have to worry about the myriad ways that exceptions can be embedded within other exceptions.
Hopefully somebody else can add something more definite.
Throwing RuntimeException or any of its subclasses will rollback a transaction. In this case you don't need to call setRollbackOnly.
If you throw application exception (non-RuntimeException), and if you want to rollback a TX at that moment, calling setRollbackOnly() is required.
Just remember that throwing a EJBException will invalidate that EJB(e.g the container will remove it) so you can't call it again. If the exception is a application (to show the user that there is something wrong, validation error) it better to call setRollbackOnly. When the user recives the application exception (with should extend Exception and NOT Remote or EJBException) it can correct the problem an use the same EJB again.