Spring事务总结(二) 事务传播行为

事务传播行为

指通过@Transactional方式声明注解时,调用另一个带有事务注解的方法 (两个事务注解都生效),即嵌套事务的情况

propagation属性控制传播行为,默认值是Propagation.REQUIRED,一共有七种情况

注:以下所指的外层方法是调用者,内层方法指的是被调用的方法,这两个方法分别来自两个代理对象,事务注解都生效

propagation属性会加在内层方法的注解上,外层方法只有@Transactional

(默认)Propagation.REQUIRED: 外层如果有事务,内存就加入到该事务,外层没有事务内层就新增一个事务。

    @Override
    @Transactional
//内层方法
public Integer saveUserInfo() { UserInfo userInfo = new UserInfo(); userInfo.setUserName("测试内层"); userInfo = userInfoRepository.save(userInfo); if (true) {
        //内层方法抛出异常,事务回滚,外层内层两条数据都不会产生
throw new RuntimeException(); } return userInfo.getId(); } @Override @Transactional
//外层方法
public void test(UserInfo userInfoParam) { userInfoParam.setUserName("测试外层");
UserInfo userInfo
= userInfoRepository.save(userInfoParam);
//调用内层方法 userInfoService.saveUserInfo(); }

注意点:

这种情况下,如果内层抛出异常,而外层捕获了异常没有抛出,会抛出:

org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit

    @Override
    @Transactional
    //内层方法
    public Integer saveUserInfo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("测试内层");
        userInfo = userInfoRepository.save(userInfo);
        if (true) {
            throw new RuntimeException();
        }
        return userInfo.getId();
    }

    @Override
    @Transactional
    //外层方法
    public void test(UserInfo userInfoParam) {
        userInfoParam.setUserName("测试外层");
        UserInfo userInfo = userInfoRepository.save(userInfoParam);
        //调用内层方法
        try {
//捕获内层抛出的异常 userInfoService.saveUserInfo(); }
catch (Exception e) { e.printStackTrace(); } }

内层抛出异常后,就被标记为rollback,当外层尝试提交的事务的时候不再被允许

(常用)Propagation.REQUIRES_NEW: 创建一个新事务,如果外层有事务则将外层事务挂起,自己方法返回后事务提交完毕,外层事务继续

这种情况较为常用,能够将内层的事务独立出来。

内层事务提交后,外层事务如果再抛出异常,内层事务不会受影响而回滚。

注意点:

显然的,如果内层方法内抛出了异常会回滚,而外层方法也没有捕获内层抛出的异常,那么外层事务也会回滚。

当然,如果外层捕获了就不会受影响。

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    //内层方法
    public Integer saveUserInfo() throws RuntimeException {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("测试内层");
        userInfo = userInfoRepository.save(userInfo);
        if (true) {
            //内层回滚
            throw new RuntimeException();
        }
        return userInfo.getId();
    }

    @Override
    @Transactional
    //外层方法
    public void test(UserInfo userInfoParam) {
        userInfoParam.setUserName("测试外层");
        UserInfo userInfo = userInfoRepository.save(userInfoParam);
        //调用内层方法
        try {
            //捕获内层异常,外层不会受影响
            userInfoService.saveUserInfo();
        } catch (RuntimeException e) {

        }
    }

其他不太常用的:

Propagation.SUPPORTS外层有事务就加入,外层没有内层也就没有

Propagation.NOT_SUPPORTED:无事务,外层有事务则将外层事务挂起

Propagation.MANDATORY:外层必须有事务

调用者没有事务就会抛出异常:org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

Propagation.NEVER:外层必须没有事务

调用者有事务就会抛出异常:org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

(Hibernate不支持)PROPAGATION_NESTED:如果当前存在事务则在 嵌套事务 内执行

嵌套事务开始执行时会取得保存点savepoint,如果嵌套事务失败则回滚到此savepoint

嵌套事务随着外层事务提交而提交,外层事务回滚也会回滚

猜你喜欢

转载自www.cnblogs.com/gss128/p/12126367.html