Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UnexpectedRollBackException in Spring inner transaction

I have two classes:

@Service
@Transaction
class A {
    public void method1() {
        private B;

        try {
            save1()
            b.method2()
        } catch (SqlException e) {
            doSomeThing();
        }

       @Autowired
       public setB(){
         this.B = B;
       }
    }
}

@Service
class B {

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void method2(){
        save2()
        throw new SqlException();
    }

}

I got an SqlException as expected, but also an UnexpectedRollBackException, and the program stops. I want to know why the data persisted by save2() is not rolled back?

Is it a problem with outer transaction?

UPDATE: I tried catching UnexpectedRollBackException in class A and everything works fine. But I still need some kind of explanation why I get the exception? I suppose the outer transaction should be suspended when the inner transaction begins, so why the rollback is unexpected for the outer transaction?

Thanks.

like image 379
hawarden_ Avatar asked Oct 11 '17 08:10

hawarden_


People also ask

How do you handle UnexpectedRollbackException?

Hence the UnexpectedRollbackException. To prevent this, the only thing you need to do is catch (and swallow, if you really want to ignore this problem) the original ConstraintViolationException WITHIN the transaction. Inside the saveMyData() for example would be ok.

What does @transactional annotation do in Spring?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

How do Spring transactions work internally?

Internally, its the same as using a transaction advice (using AOP), where a proxy is created first and is invoked before/after the target bean's method. The generated proxy object is supplied with a TransactionInterceptor, which is created by Spring.

What is @transactional annotation in Spring MVC?

The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction".


1 Answers

First of all: you are not injecting the instance of B into class A via spring. i.e. your b is not managed by spring => this leads to the behaviour: Spring is ignoring the @Transactional annotation on method.

Second if you don't want to rollback on SqlException you have to specify noRollbackFor=SqlException.class

UPDATE: after clarification, the call is happening on managed bean. But the problem that expected behaviour - transaction inside of transaction is not supported in general by the transaction management system out of the box. https://docs.spring.io/spring/docs/4.3.11.RELEASE/javadoc-api/org/springframework/transaction/annotation/Propagation.html#REQUIRES_NEW

Unless the details on that system are provided it is impossible to step forward. Out of content the NESTED transaction propagation could be better, then REQUIRES_NEW, because it is making a rollback point for the external transaction and starts new one.

like image 184
Ilya Dyoshin Avatar answered Oct 30 '22 22:10

Ilya Dyoshin