Spring Boot 事务回滚注意事项

想实现回滚,首先要保证 Spring Boot 开启了事务(在启动类上增加 @EnableTransactionManagement 注解开启事务(其实 Spring Boot 默认就是开启事务的),其次就是实现回滚的方法必须是 public 的。 @Transactional(rollbackFor=Exception.class) 表示的是该方法无论抛出什么异常都会进行自动回滚;如果不加 (rollbackFor=Exception.class) 的话,则代表了默认值,也就是只有当该方法抛出了运行时异常(RuntimeException)时才会进行回滚。 由于事务的四大特性(原子性、一致性、隔离性、持久性),所以 @Transactional 一般是要加在业务层(也就是接口实现类)中。 如果将 @Transactional(rollbackFor=Exception.class) 加在了接口实现类上,那么这个类下的所有方法都将会被加上事务管理,即所有方法都会在自己出现异常时进行回滚操作。

/**
 * 插入会员信息
 * 
 * @param cashierMember 会员信息
 * @return 结果
 */
@Override
@Transactional(rollbackFor = Exception.class)
public int insertCashierMember(CashierMember cashierMember)
{
    cashierMember.setCreateTime(DateUtils.getNowDate());
    cashierMember.setCreateBy(ShiroUtils.getLoginName());
    SMSUtil.sendCreateMemberMessage(cashierMember.getPhonenumber());
    return cashierMemberMapper.insertCashierMember(cashierMember);
}

很多方法中都会用 try-catch 对异常进行处理,如果此时在 catch 中对可能出现的异常进行了处理,但是并没有再手动抛出(throw)异常,Spring 则会认为该方法成功执行,也就不会进行回滚👇

正解如下👇

/**
 * 插入会员信息
 * 
 * @param cashierMember 会员信息
 * @return 结果
 */
@Override
@Transactional(rollbackFor = Exception.class)
public int insertCashierMember(CashierMember cashierMember)
{
    try {
        cashierMember.setCreateTime(DateUtils.getNowDate());
        cashierMember.setCreateBy(ShiroUtils.getLoginName());
        SMSUtil.sendCreateMemberMessage(cashierMember.getPhonenumber());
        return cashierMemberMapper.insertCashierMember(cashierMember);
    }catch (Exception e){
        System.out.println("方法出现异常:" + e);
        //手动抛出异常
        throw new RuntimeException();
    }
}

P.S. 如果 try-catch 语句在 finally 语句块中进行了 return 操作,那么 catch 语句块中手动抛出的异常也会被覆盖,同样不会自动回滚。

手动回滚

手动回滚的实现方式也非常简单,只需要添加一句代码即可实现👇

/**
 * 插入会员信息
 * 
 * @param cashierMember 会员信息
 * @return 结果
 */
@Override
@Transactional(rollbackFor = Exception.class)
public int insertCashierMember(CashierMember cashierMember)
{
    try {
        cashierMember.setCreateTime(DateUtils.getNowDate());
        cashierMember.setCreateBy(ShiroUtils.getLoginName());
        SMSUtil.sendCreateMemberMessage(cashierMember.getPhonenumber());
        return cashierMemberMapper.insertCashierMember(cashierMember);
    }catch (Exception e){
        System.out.println("方法出现异常:" + e);
        //实现手动回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
    return 0;
}
经验分享 程序员 微信小程序 职场和发展