@Transactional失效场景

1、事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚。

代码示例

@Override
    @Transactional
    public ResponseTemplate add(String grantUser){
        AuthEntity authEntity = JSON.parseObject(grantUser, AuthEntity.class);
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm");
            Date start_due = format.parse(authEntity.getStartTime());
            Date over_due = format.parse(authEntity.getStartTime());
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String startDue = dateFormat.format(start_due);
            String overDue = dateFormat.format(over_due);
            AgentPersonalDto personalDto = new AgentPersonalDto();
            personalDto.setPerId(authEntity.getGrantorEmpNo());
            personalDto.setFactor(authEntity.getGranteeEmpNo());
            personalDto.setStartdue(startDue);
            personalDto.setOverdue(overDue);
            personalDto.setFactorWfoid(0);
            personalDto.setProId("js");
            JSONObject jsonObject = null;
            jsonObject = agentPersonalService.updateFormData(personalDto);
            AgentPersonalDto agentPersonalDto = (AgentPersonalDto) jsonObject.get("form");
            authEntity.setCfgPersonalId(agentPersonalDto.getId());
            int i = 1/0;
            goOutAuthorizationMapper.insert(authEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResSuccessTemplate.builder().data(authEntity.toString()).build();
    }

测试代码

@Test
    public void test(){
        String grantUser ="{dataId:'11a8bc95-7872-419c-8e50-78a21930b2e1', grantorName: '张三',  grantorId: 'zhangsan',  grantorEmpNo: '23000000', grantorDeptCode:'00230057000000000000', grantorDeptName:'办公室',startTime: '20170705 18:00', endTime: '20170706 18:00', granteeName: '李四', granteeId: 'lisi', granteeEmpNo: '23000001',granteeDeptCode:'00230057000000000000', granteeDeptName:'办公室',systemId:'OA'}";
        ResponseTemplate add = null;
        try {
            add = goOutAuthorizationService.add(grantUser);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("----------------"+add);
    }

运行测试用例发现,虽然抛出异常,但是异常被捕捉了,没有抛出到方法外,所以goOutAuthorizationService.add(grantUser)操作并没有回滚。

解决方案

@Transactional(rollbackFor = Exception.class)

事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚。

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)  
      throws Throwable {  
  
   // If the transaction attribute is null, the method is non-transactional.  
   final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);  
   final PlatformTransactionManager tm = determineTransactionManager(txAttr);  
   final String joinpointIdentification = methodIdentification(method, targetClass);  
  
   if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {  
      // Standard transaction demarcation with getTransaction and commit/rollback calls.  
       //开启事务  
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);  
      Object retVal = null;  
      try {  
         // This is an around advice: Invoke the next interceptor in the chain.  
         // This will normally result in a target object being invoked.  
          //反射调用业务方法  
         retVal = invocation.proceedWithInvocation();  
      }  
      catch (Throwable ex) {  
         // target invocation exception  
          //异常时,在catch逻辑中回滚事务  
         completeTransactionAfterThrowing(txInfo, ex);  
         throw ex;  
      }  
      finally {  
         cleanupTransactionInfo(txInfo);  
      }  
       //提交事务  
      commitTransactionAfterReturning(txInfo);  
      return retVal;  
   }  
  
   else {  
     //....................  
   }  
}  

如上所述:
事务想要回滚,必须能够在这里捕捉到异常才行,如果异常中途被捕捉掉,那么事务将不会回滚。

@Transactional注解指定了 rollbackFor为某个具体的异常类型,则最终需要保证异常时对外抛出相匹配的异常类型,就可以触发事务处理逻辑。

2、Transactional注解标注方法修饰符为非public时,@Transactional注解会不起作用。

@Test
    @Transactional
    void test(){
        String grantUser ="{dataId:'11a8bc95-7872-419c-8e50-78a21930b2e1', grantorName: '张三',  grantorId: 'zhangsan',  grantorEmpNo: '23000000', grantorDeptCode:'00230057000000000000', grantorDeptName:'办公室',startTime: '20170705 18:00', endTime: '20170706 18:00', granteeName: '李四', granteeId: 'lisi', granteeEmpNo: '23000001',granteeDeptCode:'00230057000000000000', granteeDeptName:'办公室',systemId:'OA'}";
        ResponseTemplate add = null;
        try {
            add = goOutAuthorizationService.add(grantUser);
            int i = 1/0;
            add = goOutAuthorizationService.add(grantUser);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("----------------"+add);
    }

@Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用。@Transactional是基于动态代理实现的,@Transactional注解实现原理中分析了实现方法,在bean初始化过程中,对含有@Transactional标注的bean实例创建代理对象,这里就存在一个spring扫描@Transactional注解信息的过程,标注@Transactional的方法如果修饰符不是public,那么就默认方法的@Transactional信息为空,那么将不会对bean进行代理对象创建或者不会对方法进行代理调用

3、在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启。

@Override
    @Transactional
    public ResponseTemplate add(String grantUser) throws Exception {
        AuthEntity authEntity = JSON.parseObject(grantUser, AuthEntity.class);
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm");
        Date start_due = format.parse(authEntity.getStartTime());
        Date over_due = format.parse(authEntity.getStartTime());
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startDue = dateFormat.format(start_due);
        String overDue = dateFormat.format(over_due);
        AgentPersonalDto personalDto = new AgentPersonalDto();
        personalDto.setPerId(authEntity.getGrantorEmpNo());
        personalDto.setFactor(authEntity.getGranteeEmpNo());
        personalDto.setStartdue(startDue);
        personalDto.setOverdue(overDue);
        personalDto.setFactorWfoid(0);
        personalDto.setProId("js");
        JSONObject jsonObject = null;
        //创建外出授权
        jsonObject = agentPersonalService.updateFormData(personalDto);
        AgentPersonalDto agentPersonalDto = (AgentPersonalDto) jsonObject.get("form");
        authEntity.setCfgPersonalId(agentPersonalDto.getId());
        int i = 1 / 0;
        //插入外出授权记录
        goOutAuthorizationMapper.insert(authEntity);
        return ResSuccessTemplate.builder().data(authEntity.toString()).build();
    }

    @Override
    public ResponseTemplate delete() throws Exception {
        return this.add("");
    }

既然事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了。

4、Spring事务控制,配置手动回滚


  try{ 
      //出现异常
  } catch (Exception e) {
       e.printStackTrace();
      //设置手动回滚
       TransactionAspectSupport.currentTransactionStatus()
               .setRollbackOnly();
  }
 //此时return语句能够执行
 return  xxx;

当我们需要在事务控制的service层类中使用try catch 去捕获异常后,就会使事务控制失效,因为该类的异常并没有抛出,就不是触发事务管理机制。怎样才能即使用try catch去捕获异常,而又让出现异常后spring回滚呢,这里就要用到

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值