views:

262

answers:

2

I'm looking for generic code pattern to properly handle transaction with respect to possible exception. I assume there is common code pattern for that, no matter what concrete kind of transaction we are dealing with.

I have a method that executes something in transaction and want to rethrow Exception that may occur when inside transactional code block. Here is an example of such method:

protected void doIt() {
  // for JDBC connection transaction may be started automatically
  // but assume we start it here
  Tran tran = session.beginTran();
  try {
    // here comes code that does some processing
    // modifies some data in transaction
    // etc.

    // success - so commit
    tran.commit();

  } catch (Exception ex) { // many different exceptions may be thrown
                           // subclass of RuntimeException, SQLException etc.
     // error - so rollback
     tran.rollback();

     // now rethrow ex
     throw ex;              // this line causes trouble, see description below
  }      
}

Now - there is compile error in method doIt. It must declare throws Exception but this is not acceptable because method doIt is used in many places and adding throws Exception leads to subsequent modifications in places of direct and indirect use of doIt. It's because of known Java Language design problem with declared exceptions.

Now the question: how to change exception vs transaction handling code to achieve my goal - properly handle transaction finalization (perform commit or rollback based on success condition) and rethrow exactly the same exception that may be catched in transactional code block.

I know that I could do something like throw new RuntimeException(ex) but this throws exception of other class and I want to avoid such solution.

+5  A: 

I'd go for something like this.

protected void doIt() {
  // for JDBC connection transaction may be started automatically
  // but assume we start it here
  Tran tran = session.beginTran();
  bool success = false;
  try {
    // here comes code that does some processing
    // modifies some data in transaction
    // etc.

    // success - so commit
    tran.commit();
    success = true;
  } finally { 
     // error - so rollback
     if (! success)
       tran.rollback();
  }      
}

.. or if tran has a method where you can query the status (tran.isFinished()) or something, you don't need the bool. Any thrown exception (i.e. runtimeexception or error, if there are no checked exceptions) will just fly on by, executing the finally block on it's way up the stack.

If rollback throws exceptions, you'll need to catch those and log-em or something (a failed rollback is a very serious condition). Remember NOT to throw anything in that case, as the exception which is currently unwinding the stack will be lost.

roe
You will need to be aware of concurrency--almost all transactional systems seem to end up being used in a concurrent context, and this code doesn't seem like it defends particularly well against that...
Alex Feinman
this is a great solution.
jspcal
@Alex: what it has to do with concurrency? What is wrong with this code considering concurrency? How to "defend"? Would you please explain?
WildWezyr
@Alex Feinman: transactions are often used as a way to handle concurrency, isolating the transaction from the other threads, if you do one transaction over multiple threads then yes you need to take care. This is something which is rarely 'supported' in the sense that you need to worry about a lot yourself (alone the fact that transaction contexts are usually tacked on to a thread local doesn't make it easier), and you should probably at least consider doing it some other way.
roe
A: 

Assuming you are using Java 5+, the Spring framework has a simple annotation (@Transactional) you can use to setup transactions.

this is a snippet of what the beginning of your code you look like if you wanted to rollback on any Exception:

import org.springframework.transaction.annotation.Transactional;

@Transactional(rollbackFor = Exception.class)
protected void doIt()

The following link may help you get started if you want to use this: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html. Section 9.5.6 is the specific section for using @Transactional.

Granger44
Can i easily setup any kind of transaction? Even a custom one that is not supported by Spring?
WildWezyr