Spring事务传播

本文详细解读Spring中的事务传播行为,包括REQUIRED、REQUIRES_NEW和NESTED,通过示例阐述它们在不同场景下的执行效果和事务关联。理解这些行为有助于正确配置事务边界,确保业务一致性。
摘要由CSDN通过智能技术生成

参考博客:Spring事务传播行为详解 - SegmentFault 思否

在Spring中,支持以下7中传播行为

事务传播行为类型

说明

PROPAGATION_REQUIRED

如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

PROPAGATION_SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY

使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER

以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

PROPAGATION_REQUIRED

  • 验证在未开启事务的方法中调用propagation = Propagation.REQUIRED的方法
@RequestMapping("/t/insert")
// 测试没有开启事务,5、6都成功
public void test1() throws Exception {
    testService.insertWithoutTransaction();
}

@RequestMapping("/t/insert/exception")
// 测试没有开启事务,其中一个insert中由异常,7成功,8失败
public void test2() throws Exception {
    testService.insertWithoutTransactionException();
}
@Transactional(propagation = Propagation.REQUIRED)
public void insert(User user) {
    userMapper.insert(user);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insertException(User user) throws Exception {
    userMapper.insert(user);
    throw new RuntimeException();
}

测试结果

  • 测试在开启事务的方法中调用opagation = Propagation.REQUIRED的方法(常用)

开启事务后,opagation = Propagation.REQUIRED的方法会加入到这个事务中。

@RequestMapping("/t/insert/transaction")
// 9、10都失败
public void test1() throws Exception {
    testService.insertTransactionThrowException();
}

@RequestMapping("/t/insert/transaction/exception")
// 11、12都失败
public void test2() throws Exception {
    testService.insertTransactionException();
}

@RequestMapping("/t/insert/transaction/normal")
// 13、14成功
public void test3() throws Exception {
    testService.insertTransactionNormal();
}
@Transactional
public void insertTransactionThrowException() {
    User user = new User(9,"honghong","female");
    userService.insert(user);
    User user1 = new User(10,"honghong","female");
    userService.insert(user1);
    throw new RuntimeException();
}

@Transactional
public void insertTransactionException() {
    User user = new User(11,"honghong","female");
    userService.insert(user);
    User user1 = new User(12,"honghong","female");
    userService.insertException(user1);
}

@Transactional
public void insertTransactionNormal() {
    User user = new User(13,"honghong","female");
    userService.insert(user);
    User user1 = new User(14,"honghong","female");
    userService.insert(user1);
}

测试结果:

结论:以上试验结果我们证明在外围方法开启事务的情况下Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。

PROPAGATION_REQUIRES_NEW

  • 场景1:外围方法未开启事务,被调用的方法传播行为为Propagation.REQUIRES_NEW。有两个方法,一个正常,一个抛异常。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insert(User user) {
    userMapper.insert(user);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertException(User user) {
    userMapper.insert(user);
    throw new RuntimeException();
}
    public void insertTransactionNew() {
        User user = new User(11,"honghong","female");
        userService.insert(user);
        User user1 = new User(12,"honghong","female");
        userService.insertException(user1);
    }

测试结果:id为11的成功,id为12的失败

  • 场景2:在insertTransactionNew方法上加上事务

测试结果:与场景1相同

PROPAGATION_NESTED

  • 场景1,外围方法没加事务,被调用的方法加了propagation = Propagation.NESTED

由于外围方法没加事务,所以对于被调用方法来说就相当于Propagation.REQUIRED

    @Transactional(propagation = Propagation.NESTED)
    public void insert(User user) {
        userMapper.insert(user);
    }

    @Transactional(propagation = Propagation.NESTED)
    public void insertException(User user) {
        userMapper.insert(user);
        throw new RuntimeException();
    }

    public void insertTransactionNested() {
        User user = new User(11,"honghong","female");
        userService.insert(user);
        User user1 = new User(12,"honghong","female");
        userService.insertException(user1);
    }

测试结果:id为11的入库成功

  • 场景二:外围方法加上了事务,被调用的方法也加了propagation = Propagation.NESTED
    @Transactional(propagation = Propagation.NESTED)
    public void insert(User user) {
        userMapper.insert(user);
    }

    @Transactional(propagation = Propagation.NESTED)
    public void insertException(User user) {
        userMapper.insert(user);
        throw new RuntimeException();
    }
    @Transactional
    public void insertTransactionNested() {
        User user = new User(11,"honghong","female");
        userService.insert(user);
        User user1 = new User(12,"honghong","female");
        userService.insertException(user1);
    }
  • 测试结果:11和12都没有成功,因为NESTED是外围方法的子事务,插入12号的时候出现了异常,外围方法事务会回滚,所以子事务也会回滚。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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、付费专栏及课程。

余额充值