Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rollback to savepoint nested transactions using Hibernate

I have a JavaEE application using Hibernate to connect to the database. In some part of my application I have calls to method which have a @Transactional annotation. In some of these cases, I want to rollback the whole transaction (the outer-service-method call, and the inner). And on some occasions I want to rollback only the inner service-method call (that is, rollback to savepoint defined at the start of the internal method).

The first part is already in place, but I have a problem with the second one. When I do the following, I get a "UnexpectedRollbackException" with the message "Transaction rolled back because it has been marked as rollback-only".

@Service
public class OuterService{

    @AutoWired
    private InnerServcie innerService; 

    @Transactional
    public void outer(){
        try{
            innerService.inner();
        }catch(RuntimeException e){
            //if i dont throw this up, it will give me the "UnexpectedRollbackException"
            System.out.println("I cought a RuntimeException");
        }
    }
}

@Service
public class InnerServcie{
    @Transactional
    public void inner(){
        //here we insert some data into db using hibernate
        //but something goes wrong and an exception is thrown
    }
}
like image 616
hfm Avatar asked Nov 25 '13 16:11

hfm


1 Answers

The feature you are looking for is called savepoints. They are not, strictly saying, nested transactions, but milestones in the consequent SQL instruction chain, to which you can rollback. Rolling back to savepoint means invalidating ALL instructions issued from the moment of creating the savepoint, so you can have multiple savepoints, but you can only rollback instructions between now and savepoint, not between 2 savepoints!

Spring supports savepoints, both when using JdbcTransactionObjectSupport manually, and using @Transactional annotation.

According to the document http://docs.spring.io/spring/docs/2.5.3/reference/transaction.html point 9.5.7.3 you should use Propagation.NESTED.

However, that options may not be available in your case. From Javadoc:

Note: Actual creation of a nested transaction will only work on specific transaction managers. Out of the box, this only applies to the JDBC DataSourceTransactionManager when working on a JDBC 3.0 driver. Some JTA providers might support nested transactions as well.

As last resort, you can issue SQL instructions starting/rollbacking to savepoint directly.

For PostgreSQL it would be:

SAVEPOINT foo;

ROLLBACK TO SAVEPOINT foo;

Source: http://www.postgresql.org/docs/8.2/static/sql-rollback-to.html

like image 175
Danubian Sailor Avatar answered Sep 30 '22 08:09

Danubian Sailor