一 非嵌套事务
如果是单事务的话,一般在方法上加上@Transactional注解就可以使改方法进行生效,使用也是比较简单的,但是如果牵涉到一个
方法里面调用了里一个服务里面的方法,且该方法上面也加上了@Transactional注解,这个时候,事物就可能不一定生效了,看下面的代码
ServiceA {
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
void methodB() {
}
}
如果这个时候,methodB方法出现了异常,只会导致methodB方法进行回滚,但是methodA方法可能会正常被提交,也有可能会出现失败回滚,具体要分场景讨论
二 嵌套事务回滚机制
针对一个方法调用另一个方法,如果一个方法发生了事物回滚,会不会导致全局事物回滚,要看具体情况分析,下面就分析各种场景不同导致的结果不同
1 业务A的方法的事务级别为PROPAGATION_REQUIRED,业务B的方法的事务级别为PROPAGATION_REQUIRED
1、如果ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,会共用同一个事务,如果出现异常,ServiceA.methodA和ServiceB.methodB作为一个整体都将一起回滚。
2、如果ServiceA.methodA没有事务,ServiceB.methodB就会为自己分配一个事务。ServiceA.methodA中是不受事务控制的。如果出现异常,ServiceB.methodB不会引起ServiceA.methodA的回滚。
2 业务A的方法的事务级别为PROPAGATION_REQUIRED,业务B的方法的事务级别为PROPAGATION_REQUIRED_NEW
1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。
2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
3 业务A的方法的事务级别为PROPAGATION_REQUIRED,业务B的方法的事务级别为PROPAGATION_REQUIRED_NETESED
调用ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的子事务并设置savepoint
1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB也将回滚。
2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
三 事务可能不生效以及注意解决方案
1 事务不生效的原因,一般对于单个事务可能是因为内部使用了try catch处理机制,导致事务失效,还有一种可能是基于使用了嵌套事务,配置不合理导致事务失效
2 事务生效的具体可能分析
第一种情况:同一个类中 一个方法无嵌套方法
如果方法名上加上@Transactional注解,方法内不要用try catch ;如果必须要用try catch ,则catch中必须用throw new RuntimeException()。否则事务不起作用。
第二种情况:同一个类中 方法A嵌套方法B
方法A有@Transactional,方法内都没有try catch,事务起作用。
方法A有@Transactional和try catch,并且catch中用throw new RuntimeException(),事务起作用。
第三种情况:不同类中,方法C嵌套方法B
方法B上加上@Transactional注解,方法内不要用try catch ;如果必须要用try catch ,则catch中必须用throw new RuntimeException()。否则方法B的事务不起作用。
方法C上加上@Transactional注解,方法内不要用try catch ;如果必须要用try catch ,则catch中必须用throw new RuntimeException(),此时方法B怎么写都行。否则方法C的事务不起作用。
3 总结,如果想确保事务生效,一般如果使用try...catch...处理机制的话,一定要throw相关异常,否则如果异常都被处理了,可能会导致事务不能回滚