Spring事务传播

Spring事务传播

Spring 事务传播性是指当多个含有事务的方法嵌套调用时,这多个方法处理事务的规则。如下图所示,事务方法之间调用,如何处理之间的事务。

在这里插入图片描述

事务传播方式

  1. PROPAGATION_REQUIRED

    这个传播行为是 Spring 默认的事务传播行为,它指的是如果外层调用方法已经开启了事务,那么当前方法就加入到外层事务。如果外层调用方没有开启事务,那么当前方法就开启一个事务。

  2. PROPAGATION_REQUIRES_NEW

    这个传播行为是每次都新开启一个事务。如果外层调用方已经开启了事务,就先把外层的事务挂起,然后执行当前新事务,执行完毕后再恢复上层事务的执行。

  3. PROPAGATION_SUPPORTS

    这个传播行为是指,如果外层调用方开启了事务,那当前方法加入到外层事务。如果外层不存在事务,那么当前方法也不会创建新事务,直接使用非事务方式执行。

  4. PROPAGATION_NOT_SUPPORTED

    这个传播行为不支持事务。也就是如果外层调用者开启了事务,就挂起外层事务 ,然后以非事务方式执行当前方法逻辑,等执行完毕后,再恢复外层事务的执行。

  5. PROPAGATION_NEVER

    这个传播行为不支持事务。也就是说如果外层调用者开启了事务,就执行当前方法前会抛出异常。

  6. PROPAGATION_MANDATORY

    这个传播行为是说,配置了这个传播性的方法只能在已经存在事务的方法中被调用。如果在不存在事务的方法中被调用,会抛出异常。

  7. PROPAGATION_NESTED

    当外层调用方存在事务时,当前方法合并到外层事务,如果外层不存在事务,就当前开启事务,这点和 PROPAGATION_REQUIRED 传播性一致,不同的是,PROPAGATION_NESTED传播行为的特点是可以保存状态保存点,当事务回滚时,可以回滚到某一个保存点上,从而避免所有嵌套事务都回滚。

PROPAGATION_REQUIRED

这个传播行为是 Spring 默认的事务传播行为,它指的是如果外层调用方法已经开启了事务,那么当前方法就加入到外层事务。如果外层调用方没有开启事务,那么当前方法就开启一个事务。

在这里插入图片描述

@Service
@Slf4j
public class ServiceA {
    @Autowired
    private ServiceB serviceB;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void methodA1() {
        //1.1做自己的入库操作
        insert();
        log.info("save something to db");
        //1.2调用服务B的入库操作
        try{
            serviceB.methodB1();
        }catch (Exception e){
            log.error("B异常了");
        }

    }
}

@Service
@Slf4j
public class ServiceB {

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void methodB1() {
        insert();
        log.info("save something to db");
        //抛出异常
        //throw new RuntimeException();
    }
}
private void insert(){
        String sql = "insert into users(name) values(?)";
        int count = jdbcTemplate.update(sql,"郭靖");
        log.info("新增条数:{}",count);
    }

当事务方法A对事务方法B捕获异常并处理,并没有将异常抛出当前事务A之外,则事务A会提交。若没有捕获则事务A会进行回退。

PROPAGATION_REQUIRES_NEW

这个传播行为是每次都新开启一个事务。如果外层调用方已经开启了事务,就先把外层的事务挂起,然后执行当前新事务,执行完毕后再恢复上层事务的执行。

在这里插入图片描述

先开启事务A,然后执行方法A。

调用方法B前,挂起事务A,开启事务B,执行方法B。

此时方法B抛出异常,会回退事务B。

重新进入事务A,若异常被捕获,则提交事务A,若无,则回退事务A.

@Service
@Slf4j
public class ServiceA {
    @Autowired
    private ServiceB serviceB;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void methodA1() {
        //1.1做自己的入库操作
        insert();
        log.info("save something to db");
        //1.2调用服务B的入库操作
        try{
            serviceB.methodB1();
        }catch (Exception e){
            log.error("B异常了");
        }

    }
}

@Service
@Slf4j
public class ServiceB {

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED_NEW)
    public void methodB1() {
        insert();
        log.info("save something to db");
        //抛出异常
        throw new RuntimeException();
    }
}
// 结果:插入了一条数据

PROPAGATION_SUPPORTS

这个传播行为是指,如果外层调用方开启了事务,那当前方法加入到外层事务。如果外层不存在事务,那么当前方法也不会创建新事务,直接使用非事务方式执行。

在这里插入图片描述

例(1)外层方法A有事务

@Service
@Slf4j
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void methodA3_1() {
        //1.1做自己的入库操作
        insert();
        log.info("save something to db");
        //1.2调用服务B的入库操作
        try{
            serviceB.methodB3_1();
        }catch (Exception e){
            log.error("B异常了");
        }
    }
}
@Service
@Slf4j
public class ServiceB {

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
    public void methodB3_1() {
        insert();
        log.info("save something to db");
        //抛出异常
        throw new RuntimeException();
    }
}

结果:无结果插入

INFO 6764 --- [           main] com.example.demo.service.ServiceA        : 新增条数:1
INFO 6764 --- [           main] com.example.demo.service.ServiceA        : save something to db
INFO 6764 --- [           main] com.example.demo.service.ServiceB        : 新增条数:1
INFO 6764 --- [           main] com.example.demo.service.ServiceB        : save something to db
ERROR 6764 --- [           main] com.example.demo.service.ServiceA        : B异常了
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

(2)外层无事务

结果:两条结果都插入

INFO 6764 --- [           main] com.example.demo.service.ServiceA        : 新增条数:1
INFO 6764 --- [           main] com.example.demo.service.ServiceA        : save something to db
INFO 6764 --- [           main] com.example.demo.service.ServiceB        : 新增条数:1
INFO 6764 --- [           main] com.example.demo.service.ServiceB        : save something to db
ERROR 6764 --- [           main] com.example.demo.service.ServiceA        : B异常了

PROPAGATION_NOT_SUPPORTED

这个传播行为不支持事务。也就是如果外层调用者开启了事务,就挂起外层事务 ,然后以非事务方式执行当前方法逻辑,等执行完毕后,再恢复外层事务的执行。

在这里插入图片描述

PROPAGATION_NEVER

这个传播行为不支持事务。也就是说如果外层调用者开启了事务,就执行当前方法前会抛出异常。

在这里插入图片描述

PROPAGATION_MANDATORY

这个传播行为是说,配置了这个传播性的方法只能在已经存在事务的方法中被调用。如果在不存在事务的方法中被调用,会抛出异常。

在这里插入图片描述

PROPAGATION_NESTED

当外层调用方存在事务时,当前方法合并到外层事务,如果外层不存在事务,就当前开启事务,这点和 PROPAGATION_REQUIRED 传播性一致,不同的是,PROPAGATION_NESTED传播行为的特点是可以保存状态保存点,当事务回滚时,可以回滚到某一个保存点上,从而避免所有嵌套事务都回滚。

Spring事务传播是指在多个具有事务控制的service相互调用时所形成的复杂事务边界控制。Spring提供了七种事务传播行为,分别是: 1. REQUIRED(默认):表示当前方法必须在一个具有事务的上下文中运行,如果客户端有事务在进行,那么被调用端将在该事务中运行,否则重新开启一个事务。如果被调用端发生异常,调用端和被调用端事务都将回滚。 2. SUPPORTS:表示当前方法可以在一个具有事务的上下文中运行,也可以在没有事务的上下文中运行。 3. MANDATORY:表示当前方法必须在一个具有事务的上下文中运行,如果没有事务则抛出异常。 4. REQUIRES_NEW:表示当前方法必须运行在它自己的事务中。一个新的事务将启动,如果有现有的事务在运行,则该方法被挂起,直到新的事务提交或回滚才恢复执行。 5. NOT_SUPPORTED:表示当前方法不应该运行在一个事务中,如果有事务在运行,则将该事务挂起,直到方法执行完毕。 6. NEVER:表示当前方法不应该运行在一个事务中,如果有事务在运行,则抛出异常。 7. NESTED:表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务存在,并且外层事务回滚,那么内层事务必须回滚,反之,内层事务不影响外层事务。如果封装事务不存在,则与REQUIRED相同。 这些事务传播行为可以根据具体的业务需求来选择,以实现正确的事务控制。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值