欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring @Transaction事务回滚失败

程序员文章站 2022-06-20 17:39:38
今天客户提出一个新问题,出库一批商品,提示失败了,但是库存数量却减少了。看了一下代码一头雾水,我们的代码加了事物,且捕获异常。 经过调试代码发现就是两个原因导致的 第一、在当前方法的catch中处理了捕获的异常,没有向上抛出异常,事务不能回滚 分析: 1.在Java中异常的基类为Throwable, ......

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

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

第一、在当前方法的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();//就是这一句了,加上之后如果异常后会回滚的  
     }