java异常捕捉陷阱(事务的异常,内存泄漏,finally块,catch块,继承得到的异常)

事务的异常回滚

默认spring只在发生未被捕获的runtimeexcetpion时才回滚。

1、事务不是遇到所有异常都会回滚,默认只有遇到遇到运行异常(RuntimeException)和程序错误(Error)才会回滚,非运行异常必须在

@Transactional 注解中使用 rollbackFor 属性来指定异常,比如:@Transactional(rollbackFor = Exception.class),才会回滚。

2、我们在处理异常时,有两种方式,要么抛出去,让上一层来捕获处理;要么把异常 try...catch 掉,在异常出现的地方给处理掉。就因为有这个 try...catch,所以导致异常被 “吃” 掉,事务无法回滚。遇到异常直接往上抛,给上一层来处理即可,千万不要在事务中把异常自己 ”吃“ 掉。

今天有个业务逻辑流程为:

1.访客预约确认先更新预约状态为“预约确认”

2.调用http接口发短信、更新预约状态为“预约成功”等一系列操作

这里面有个问题,如果第2步调接口异常或返回失败。则第1步需要回滚。开始我的代码如下:

    public void updateStatusConfirm(int id) throws Exception {
        appointmentMapper.updateStatusConfirm(id);
        String res = Httper.get(appConfirmUrlPre + URL_SUFFIX + id);
        log.info("预约确认接口返回值为:" + res);
        if (StringUtils.isBlank(res) || !"0".equals(JSON.parseObject(res).getString("resultCode"))) {
            throw new Exception("预约确认接口返回失败,请稍后重试!");
        }
    }

结果发现第1步执行成功,而第2步返回失败,事务并没有回滚。

后来才发现,捕获了异常不会发生事务回滚,除非抛出RuntimeException异常,更改代码如下:

    public void updateStatusConfirm(int id) throws Exception {
        appointmentMapper.updateStatusConfirm(id);
        String res = Httper.get(appConfirmUrlPre + URL_SUFFIX + id);
        log.info("预约确认接口返回值为:" + res);
        if (StringUtils.isBlank(res) || !"0".equals(JSON.parseObject(res).getString("resultCode"))) {
            throw new RuntimeException("预约确认接口返回失败,请稍后重试!");
        }
    }

就可以了。

这也意味着在service层最好不要捕获异常,否则不会回滚。

如捕获异常时,需要回滚需加上:代码级控制:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

try{
...
}catch(Exception e){
   log.error(e.getMessage(),e);
   TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
   throw new RuntimeException( e.getMessage(), e );
  } 

https://blog.csdn.net/qingmengwuhen1/article/details/80969781

java异常捕捉陷阱(内存泄漏,finally块,catch块,继承得到的异常)

https://blog.csdn.net/zshake/article/details/9207791

posted @ 2020-04-12 14:45  你猜lovlife  阅读(568)  评论(0)    收藏  举报