Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rollback a @Transactional annotated method

Good day. The following code:

 class A{
     private B b;
    @Transactional
    public SomeResult doSomething(){
        SomeResult res = null;
        try {
          // do something 
        } catch (Exception e) {
            res  = b.saveResult();
        }
        return res ;
    }
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
class B{
  public SomeResult saveResult(){
      // save in db 
  }
}

As I understand, if there is an exception in the method doSomething the transaction isn't rolled back. And how to make that it rolled? and returned SomeResult

like image 703
yaroslavTir Avatar asked Aug 30 '12 10:08

yaroslavTir


People also ask

How do I rollback transaction programmatically?

You can mark the transaction for rollback programmatically by injecting TransactionManager . Inject the TransactionManager and set the transaction for rollback with setRollbackOnly : In this example, the transaction context is propagated to all calls nested in the @Transactional method ( childDAO.

What happens if one @transactional annotated method is calling another @transactional annotated method on the same object instance?

If you call a method with a @Transactional annotation from a method with @Transactional within the same instance, then the called methods transactional behavior will not have any impact on the transaction.

What happens if a method annotated with @transactional calls another method annotated with transactional?

If you call a method with a @Transactional annotation from a method with @Transactional belonging to the same Spring Bean , then the called methods transactional behavior will not have any impact on the transaction.


2 Answers

You shouldn't call Rollback programmatically. The best way, as recommended by the docs, is to use declarative approach. To do so, you need to annotate which exceptions will trigger a Rollback.

In your case, something like this

@Transactional(rollbackFor={MyException.class, AnotherException.class})
public SomeResult doSomething(){
   ...
}

Take a look at the @Transaction API and the docs about rolling back a transaction.

If, despite the docs recommendation, you want to make a programmatic rollback, then you need to call it from TransactionAspectSupport as already suggested. This is from the docs:

public void resolvePosition() {
  try {
    // some business logic...
  } catch (NoProductInStockException ex) {
    // trigger rollback programmatically
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}

There may be a architecture mistake though. If your method fails and you need to throw an exception, you shouldn't expect it to return anything. Maybe you're giving too much responsibilities to this method and should create a separated one that only model data, and throws an exception if something goes wrong, rolling back the transaction. Anyway, read the docs.

like image 179
Caio Cunha Avatar answered Oct 11 '22 03:10

Caio Cunha


get TransactionStatus using TransactionAspectSupport.currentTransactionStatus() ect transaction manager to your bean try to invoke Rollback(DefaultTransactionStatus status) in transaction manager.

refer to spring documentation

You are strongly encouraged to use the declarative approach to rollback if at all possible. Programmatic rollback is available should you absolutely need it, but its usage flies in the face of achieving a clean POJO-based architecture.

like image 31
Jigar Parekh Avatar answered Oct 11 '22 01:10

Jigar Parekh