@Transactional注解的使用以及try-catch捕获异常导致@Transactional注解失效的问题

1、事务管理是应用系统开发中必不可少的一部分。在spring boot 中,使用事务非常简单,只要直接在方法上面加入@Transactional 就可以实现。

2、SpringBoot项目会自动配置一个 DataSourceTransactionManager,所以我们只需在方法(或者类)加上 @Transactional 注解,就自动纳入 Spring 的事务管理了。

如下在方法加上 @Transactional 注解:

@Transactional
public void insertUser() {
    User user = new User("张三");
    userMapper.insertOneUser(user);          //向数据库插入一条记录
    throw new RuntimeException("发生异常");   //手动模拟抛出异常
}

抛出异常之后,事务会自动回滚,数据不会插入到数据库。

  • 当Transaction内发生unchecked exception的时候,会自动rollback,但是当Transaction内发生checked exception时,是不会自动rollback的。
  • 如果使用try-catch捕获异常,则该事务不会回滚。

3、默认spring事务只在发生未被捕获的 RuntimeException 时才回滚。

spring aop异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获RuntimeException的异常,但可以通过配置来捕获特定的异常并回滚。
换句话说在service的方法中不使用try catch或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚。

解决方案:

  • 方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理。

  • 方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常。

例如

catch (Exception e)
{
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//手动回滚
    result.put("status", 0);
    result.put("msg",msg);
    return result;
}

4、总结:如果是try-catch捕获异常引起的@Transactional注解失效,只要手动抛出RuntimeException()或者在catch中使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句就可以解决。

5、参考博客:

posted @ 2020-06-25 14:30  Cancan001  阅读(7887)  评论(0编辑  收藏  举报