小鸡爪偶遇Spring事务的手动回滚

962 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

Spring事务的手动回滚

设置手动回滚

在事务方法内,在想控制回滚位置调用此方法

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()

eg:

判断某个流程执行结果,执行过程中没有报异常但是执行失败,我们手动干涉回滚

@Transactional(rollbackFor = Exception.class)
@Override
public void transactionOpen() {
    System.out.println("open");

    boolean result = personService.innerTransactionOpen();
    if (!result){
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

}

另一个用途

捕捉执行过程的异常,但也要回滚这段过程的操作

在catch里面调用此方法就能达到这种效果

@Transactional(rollbackFor = Exception.class)
@Override
public void transactionOpen() {

    System.out.println("open");
    boolean result = false;

    try {
        personService.innerTransactionOpen();
    } catch (Exception e) {
        System.out.println("吃下异常");
        System.out.println("然后回滚");
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

}

innerTransactionOpen方法执行过程发送异常,里面的更新操作也都会回滚

注意点

当有事务嵌套或者异常需要其他处理的时候,捕获后记得再抛出异常

eg:

比如有事务嵌套时候,内层事务如果捕获后回滚没有再抛异常,外层的事务会正常提交,但是因为内层事务的代码操作已经回滚,数据状态不一致,就会报错,抛出图片中的异常,虽然最后都回滚,不影响正常业务。但是这种要避免。

image.png

应该把对应的异常继续抛出,后面才能更好的处理解决

@Transactional(rollbackFor = Exception.class)
@Override
public void innerTransactionOpen() {
    Person person = createPerson();

    try {
        save(person);
    } catch (Exception e) {
        System.out.println("吃下异常");
        System.out.println("然后回滚");
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        System.out.println("继续抛出异常");
        throw e;
    }
}

题外

判断某个流程执行结果,执行回滚操作,我们也可以根据结果,抛出相应的异常或者使用断言,让事务捕捉到进行自动回滚,事务回滚后会继续抛出异常,我们再进行异常的统一处理。