Spring的7种事务传播方式

Spring事务传播行为体现在某个service方法调用另一个service方法,事务该如何进行下去。

Spring支持7中事务传播方式,在Propagation类中可以看到,如下:

REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);

使用方式就是在service方法上加入Transational注解,例如:

@Transactional(propagation = Propagation.NOT_SUPPORTED)

下面逐个介绍下这7中事务传播方式:

1. REQUIRED:

Spring的默认事务传播方式。从字面意思看,它表示此枚举修饰的service方法必须运行在一个事务中,如果当前存在一个事务(比如其他有事务的service方法调用此方法),则运行在当前事务中,否则开启一个新的事务。

示例代码如下:

注意:这里methodA调用methodB必须要用Spring的代理方式,即用testService.methodB()方式调用,如果只是method()方式调用则相当于this.methodB()在本对象中调用,事务不起作用的,一定要是Spring的AOP代理。@Lazy注解是为了防止启动的时候出现循环依赖报错,采用懒加载方式注入Bean。

下面示例中,methodA调用methodB的时候,会先开启一个事务,methodB中会使用methodA这个事务,和methodA一起提交或回滚。

@Service
public class TestServiceImpl implements TestService {

    @Resource @Lazy
    private TestService testService;

    @Transactional
    @Override
    public void methodA() {
        testService.methodB();
        System.out.println("CRUD operation in methodA...");
    }

    @Transactional
    @Override
    public void methodB() {
        System.out.println("CRUD operation in methodB...");
    }
}

2. SUPPORTS:

从字面意思看,它是支持的意思,也就是有事务我也支持,没有也行。

即:调用此方法时如果有一个事务,那么就在当前事务中执行,和当前事务一起提交或回滚。如果当前没有事务,那么就不开启事务,在无事务环境中执行。

下面示例代码中,methodB是SUPPORTS事务传播方式,methodB有没有事务取决于调用它的methodA。可以看到此时methodA是有一个事务的,所以methodB会在methodA这个事务中一起提交或回滚。

@Service
public class TestServiceImpl implements TestService {

    @Resource @Lazy
    private TestService testService;

    @Transactional
    @Override
    public void methodA() {
        testService.methodB();
        System.out.println("CRUD operation in methodA...");
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public void methodB() {
        System.out.println("CRUD operation in methodB...");
    }
}

3. MANDATORY:

字面意思:强制。

没错,就是一定要在事务中执行,否则就会抛异常。

如下面的代码,如果直接调用methodB,由于当前没有事务,会抛出一个IllegalTransactionStateException异常。如果是在methodA中调用methodB,由于methodA开启了一个事务,所以methodB会在methodA的事务中执行,不会报错。

@Service
public class TestServiceImpl implements TestService {

    @Resource @Lazy
    private TestService testService;

    @Transactional
    @Override
    public void methodA() {
        testService.methodB();
        System.out.println("CRUD operation in methodA...");
    }

    @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public void methodB() {
        System.out.println("CRUD operation in methodB...");
    }
}

4. REQUIRES_NEW:

字面意思:开启一个新的事务。

这个事务传播方式会挂起当前事务,开启一个新的事务,方法会在新的事务中执行并提交,提交完之后,挂起的事务继续往下走。

如下代码,methodA调用methodB的时候,当前事务会被挂起,然后在methodB中会开启一个新的事务,methodB执行完并且事务提交后,methodA的事务继续执行。methodB回滚不影响methodA,methodA回滚也不影响methodB。

    @Transactional
    @Override
    public void methodA() {
        testService.methodB();
        System.out.println("CRUD operation in methodA...");
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void methodB() {
        System.out.println("CRUD operation in methodB...");
    }

5. NOT_SUPPORTED:

字面意思:不支持事务。

用该枚举修饰的方法一定会运行在非事务环境中,即使调用此方法时有一个事务,也会将该事务挂起。我们通常将这种方式应用于强制要求非事务的方法中,例如我们现在要将批量数据去集成第三方接口然后更新状态到DB,不能说某一个数据出错就导致所有数据状态都回滚,那样的话,已经成功集成过第三方接口的数据就又得重新去集成了,会造成重复调用,导致第三方系统中的数据混乱。

如下代码,methodA有一个事务,当它调用methodB时,事务会被挂起,然后methodB中的CRUD操作不会在事务中执行,会立即提交到数据库。methodB执行完之后,methodA的事务继续进行,methodA的回滚不影响methodB。

    @Transactional
    @Override
    public void methodA() {
        testService.methodB();
        System.out.println("CRUD operation in methodA...");
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public void methodB() {
        System.out.println("CRUD operation in methodB...");
    }

6. NEVER:

字面意思:永远也不在事务中运行。

该枚举修饰的方法一旦在事务环境中就会抛异常。

7. NESTED:

字面意思:嵌套事务。

这种传播方式稍微有点复杂,目前各种厂商对它的支持可能存在差异,需要看具体的事务管理实现方式。

用此枚举修饰的方法,当外部有事务的时候,会在里面嵌套一个事务,里面的事务回滚不会影响外部事务,但外部事务出错回滚会将里面的也一起回滚。

如下methodB会在methodA的事务里面再嵌套一个事务,当methodA事务提交,methodB也会跟着一起提交,当methodA出错回滚,会把methodB也一起回滚。当methodB出错回滚,不会影响methodA的事务,事务会回退到调用methodB前的节点,然后继续处理后续的步骤。

    @Transactional
    @Override
    public void methodA() {
        System.out.println("CRUD operation in methodA before...");
        //保存当前状态,开启嵌套事务
        try {
            testService.methodB();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //methodB回滚后不影响methodA事务继续进行
        System.out.println("CRUD operation in methodA...");
    }

    @Transactional(propagation = Propagation.NESTED)
    @Override
    public void methodB() {
        System.out.println("CRUD operation in methodB...");
        throw new RuntimeException("methodB rollback");
    }

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Spring事务传播方式是指在一个service方法调用另一个service方法时,事务如何进行传播。Spring的默认事务传播方式是PROPAGATION_REQUIRED。这意味着如果当前存在一个事务(比如其他有事务的service方法调用此方法),则该方法将运行在当前事务中,否则将开启一个新的事务。 需要注意的是,调用methodB的方法必须使用Spring的代理方式,即用testService.methodB()方式调用,如果只是普通方法调用(比如this.methodB()),事务将不会起作用。同时,可以使用@Transactional注解来标注需要进行事务管理的方法。 在一些特殊情况下,可以使用其他的事务传播方式。例如,当methodA调用methodB时,当前事务会被挂起,然后在methodB中会开启一个新的事务。methodB执行完并且事务提交后,methodA的事务继续执行。这情况下,可以在methodB上使用@Transactional(propagation = Propagation.REQUIRES_NEW)来设置事务传播方式。 总结起来,Spring提供了多事务传播方式,根据具体需求可以选择合适的方式来管理事务。默认的传播方式是PROPAGATION_REQUIRED,即如果当前存在一个事务,则在该事务中运行,否则开启一个新的事务。同时,需要使用Spring的代理方式调用有事务管理的方法才能确保事务的正确运行。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值