spring @Transaction事务回滚失败

2022-10-13,,,

今天客户提出一个新问题,出库一批商品,提示失败了,但是库存数量却减少了。看了一下代码一头雾水,我们的代码加了事物,且捕获异常。

经过调试代码发现就是两个原因导致的

第一、在当前方法的catch中处理了捕获的异常,没有向上抛出异常,事务不能回滚

分析:

1.在java中异常的基类为throwable,他有两个子类exception与errors,同时runtimeexception就是exception的子类;

2.runtimeexception,即运行时异常,为非受检(unchecked)异常;      

3.exception的其他子类异常,为非运行时异常,为受检异常(checked)异常;

spring事务回滚机制是这样的:当所拦截的方法有指定异常抛出,事务才会自动进行回滚!

     ①被拦截方法-—— 注解式:方法或者方法所在类被@transactional注解;

     ②异常—— 该方法的执行过程必须出现异常,这样事务管理器才能被触发,并对此做出处理;

    ③指定异常—— 默认配置下,事务只会对error与runtimeexception及其子类这些unchecked异常,做出回滚。一般的exception这些checked异常不会发生回滚(如果一般exception想回滚要做出配置);

spring的声明式事务是基于aop的
   spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理(如果自己捕获就不能被声明式事务感知),这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过 。
    
配置来捕获特定的异常并回滚  
  换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
  解决方案: 
  方案1.方法中不做异常捕获,或者在catch语句中最后增加throw new runtimeexception()语句,以便让aop捕获异常再去回滚,并且在上层(webservice客户端,view层action)要继续捕获这个异常并处理
  方案2.在方法的catch语句中增加:transactionaspectsupport.currenttransactionstatus().setrollbackonly();语句,手动回滚,这样上层就无需去处理异常

第二、在catch中异常抛出exception,并不是runtimeexception,导致也没有回滚

解决方法:

① 抛出exception,同时在事务声明中加上@transactional(rollbackfor = exception.class)

② 在catch添加语句

catch (exception e) {  
          e.printstacktrace();     
          transactionaspectsupport.currenttransactionstatus().setrollbackonly();//就是这一句了,加上之后如果异常后会回滚的  
     }  

《spring @Transaction事务回滚失败.doc》

下载本文的Word格式文档,以方便收藏与打印。