spring事务的传播行为详细理解

本文深入探讨了Spring中的七种事务传播行为,包括REQUIRED、NEVER、MANDATORY、SUPPORTS、NOT_SUPPORTED、REQUIRES_NEW和NESTED,并通过实例解析了它们在不同场景下的应用。在事务管理中,正确设置事务传播行为对于确保业务逻辑的正确性和数据一致性至关重要。文章还提供了具体的方法A和B的示例,展示了如何在异常处理和事务回滚策略中运用这些传播行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring事务的传播行为详细理解

一,spring七中事务传播行为

 1、 REQUIRED:默认的传播特性,业务方法需要在一个事务中运行,如果一个方法已经处在一个事务中那么就加入到这个事务中,否则就会创建一个事务。

 2、 NEVER:指定的业务方法绝对不能在事务范围内运行,如果业务方法在某个事务中执行,就会抛异常,只有业务方法没有任何事务才正常执行。

 3、 MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能自己发起自己的事务,如果业务方法不存在事务,容器就抛异常。

 4、 SUPPORTS:如果业务方法中已经在某个事务中被调用,则方法就称为事务的一部分,如果外部业务方法没有开启事务,supports该方法也会在没有事务的环境中执行。

 5、 NOT_SUPPORTED如果该业务方法在一个事务中被调用,那么当前的事务会被挂起,执行该业务方法,方法执行完毕唤醒被挂起的事务,如果业务方法不在一个事务中执行,该方法也不会开事务。不管是否在有无事务的环境中执行都不开启事务。

 6、 REQUIRES_NEW:不管是否存在事务,业务方法总会自己开启一个事务,如果在已有事务的环境中调用,已有事务会被挂起,新的事务会被创建,直到业务方法调用结束,已有事务才被唤醒

 7、 NESTED:如果业务方法在一个事务中执行,就在这个事务中嵌套,如果没有事务按着required执行,开启单独的事务,这种事务有多个事务的保存点,NESTED内部事务异常会回滚 外部事务不会回滚(前提条件,外部事务将内部事务的异常捕获了,不捕获的话,两个事务都会回滚) ;内部事务没有异常,外部事务有异常 则整体事务都回滚

二、传播行为使用场景和结论

前提有两个方法,两个方法中都使用到了事务,@Transactional默认传播行为为REQUIRED

比如

A方法

@Transactional
public void A() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUserId(797220166600626176L);
    userInfo.setPassWord("laoda");
    userInfoMapper.updateByPrimaryKeySelective(userInfo);
    try {
        userLoginService.B();  // 这里需要userLoginService.B(),不能使用B(),因为A方法和B方法在一个service中,B()方法的事务会不起作用,后续分析事务失效问题
    }catch (Exception e) {
        log.info("我捕获了异常,看你能不能回滚");
    }
    int x = 1;
    if(x == 1) {
        throw new RuntimeException();
    }

}

B方法

@Transactional
public void B() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUserId(797221588868141056L);
    userInfo.setPassWord("xiaodi");
    userInfoMapper.updateByPrimaryKeySelective(userInfo);
    int x = 0;
    if(x == 1) {
        throw new RuntimeException();
    }
}

场景一 A方法和B方法都使用   propagation = Propagation.REQUIRED

@Transactional(propagation = Propagation.REQUIRED)
public void A() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUserId(797220166600626176L);
    userInfo.setPassWord("laoda");
    userInfoMapper.updateByPrimaryKeySelective(userInfo);
    try {
        userLoginService.B();
    }catch (Exception e) {
        log.info("我捕获了异常,看你能不能回滚");
    }
    int x = 0;
    if(x == 1) {
        throw new RuntimeException();
    }

}

@Transactional(propagation = Propagation.REQUIRED)
public void B() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUserId(797221588868141056L);
    userInfo.setPassWord("xiaodi");
    userInfoMapper.updateByPrimaryKeySelective(userInfo);
    int x = 0;
    if(x == 1) {
        throw new RuntimeException();
    }
}

根据不同的情况实验结论:

若两个方法都没有出现异常,则会提交成功;

A方法将b的异常捕获,若方法B出现了异常,A方法执行后会出现Transaction rolled back because it has been marked as rollback-only, 此异常出现因为方法A和方法B共用一个事务,B方法出现了异常,将事务标记为回滚,但是异常被方法A捕获了,方法A执行完要提交的时候,发现异常被标记为回滚,所以会出现此异常(事务不会提交,数据不会更新)。解决方法不要在捕获B方法的异常或者捕获后在抛出也可以(方法A和B属于同一业务逻辑)B方法使用propagation = Propagation.REQUIRES_NEW ,B方法出现异常不会影响A方法(方法A和B不属于同一业务逻辑)。

若方法A出现异常,事务都会回滚,或者若B方法出现异常并且在方法A中不使用trycatch,事务会回滚。

场景二 A方法使用   propagation = Propagation.REQUIRED, B方法使用propagation = Propagation.REQUIRES_NEW

    @Transactional(propagation = Propagation.REQUIRED)
    public void A() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(797220166600626176L);
        userInfo.setPassWord("laoda");
        userInfoMapper.updateByPrimaryKeySelective(userInfo);
//        userLoginService.B();
        try {
            userLoginService.B();
        }catch (Exception e) {
            log.info("我捕获了异常,看你能不能回滚");
        }
      // int x = 1;
     // if(x == 1) { 
      // throw new RuntimeException(); 
     // }

    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void B() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(797221588868141056L);
        userInfo.setPassWord("xiaodi");
        userInfoMapper.updateByPrimaryKeySelective(userInfo);
//        int x = 1;
//        if(x == 1) {
//            throw new RuntimeException();
//        }
    }

根据不同的情况实验结论:

若两个方法都没有出现异常,则会提交成功;

在A方法将B的异常捕获,若B方法出现异常会回滚,A方法正常提交成功;若B方法没有出现异常,事务成功提交,A方法出现异常,则A方法回滚,B方法不会回滚

在A方法中不捕获B的异常,若A出现异常 A回滚,不会影响B,B没有出现异常,B成功提交;若B出现异常。两个都会回滚

场景三、 A方法使用   propagation = Propagation.REQUIRED, B方法使用propagation = Propagation.NESTED

    @Transactional(propagation = Propagation.REQUIRED)
    public void A() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(797220166600626176L);
        userInfo.setPassWord("laoda");
        userInfoMapper.updateByPrimaryKeySelective(userInfo);
//        userLoginService.B();
        try {
            userLoginService.B();
        }catch (Exception e) {
            log.info("我捕获了异常,看你能不能回滚");
        }
        int x = 1;
        if(x == 1) {
            throw new RuntimeException();
        }

    }

    @Transactional(propagation = Propagation.NESTED) 
    public void B() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(797221588868141056L);
        userInfo.setPassWord("xiaodi");
        userInfoMapper.updateByPrimaryKeySelective(userInfo);
//        int x = 1;
//        if(x == 1) {
//            throw new RuntimeException();
//        }
    }

根据不同的情况实验结论:

若两个方法都没有出现异常,则会提交成功;

在A方法中将B的异常捕获,若B方法出现异常,B会回滚,A正常提交;若A方法出现异常,则会影响B方法,两个都会回滚

在A方法中不捕获B的异常,若B方法出现异常,A和B都会回滚;若A方法出现异常,则会影响B方法,两个都会回滚

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值