Reputation: 2170
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.
Upvotes: 7
Views: 5232
Reputation: 3807
I have a simliar scenario like this and resolved it using propagation = Propagation.NESTED
from where the second method
is calling. rewrite the code as mentioned below and try.
@Service
class A {
@Transactional(rollbackFor = { HibernateException.class}, propagation = Propagation.NESTED)
public void method1() {
private B;
try {
save1()
b.method2()
} catch (SqlException e) {
doSomeThing();
}
@Autowired
public setB(){
this.B = B;
}
}
}
Note: Transactional
is used in method level for class A
with propagation nested
. Class B
shown below.
@Service
class B {
@Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRED)
public void method2(){
save2()
throw new SqlException();
}
}
This has resolved the issue in my case.
Upvotes: 0
Reputation: 4624
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.
Upvotes: 4