出处: https://blog.csdn.net/selfsojourner/article/details/74561745

spring 事务的传播行为中,有两个容易混淆的行为:REQUIRED和REQURED_NEW。当程序在某些情况下抛出异常时,如果对于这两者不够了解,就可能很难发现而且解决问题。

下面我们给出三个场景进行分析:

场景一:

ServiceA.java:

public class ServiceA {
    @Transactional
    public void callB() {
        serviceB.doSomething();
    }
}

ServiceB.java

public class ServiceB {
    @Transactional
    public void doSomething() {
        throw new RuntimeException("B throw exception");
    }
}

这种情况下,我们只需要在调用ServiceA.callB时捕获ServiceB中抛出的运行时异常,则transaction就会正常的rollback。

场景二

在保持场景一中ServiceB不变,在ServiceA中调用ServiceB的doSomething时去捕获这个异常,如下:

public class ServiceA {
    @Transactional
    public void callB() {
        try {
            serviceB.doSomething();
        } catch (RuntimeException e) {
            System.err.println(e.getMessage());
        }
    }
}

这个时候,我们再调用ServiceA的callB。程序会抛出org.springframework.transaction.UnexpectedRollbackException:
Transaction rolled back because it has been marked as
rollback-only这样一个异常信息。原因是什么呢?

因为在ServiceA和ServiceB中的@Transactional
propagation都采用的默认值:REQUREID。根据我们前面讲过的REQUIRED特性,当ServiceA调用ServiceB的时候,他们是处于同一个transaction中。如下图所示:

当ServiceB中抛出了一个异常以后,ServiceB会把当前的transaction标记为需要rollback。但是ServiceA中捕获了这个异常,并进行了处理,认为当前transaction应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException。

场景三

在保持场景二中ServiceA不变,修改ServiceB中方法的propagation配置为REQUIRES_NEW,如下:

public class ServiceB {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomething() {
        throw new RuntimeException("B throw exception");
    }
}

此时,程序可以正常的退出了,也没有抛出UnexpectedRollbackException。原因是因为当ServiceA调用ServiceB时,serviceB的doSomething是在一个新的transaction中执行的。如下图所示:

所以,当doSomething抛出异常以后,仅仅是把新创建的transaction rollback了,而不会影响到ServiceA的transaction。ServiceA就可以正常的进行commit。

当然这里把ServiceA和ServiceB放在两个独立的transaction是否成立,还需要再多多考虑你的业务需求.

最新文章

  1. Android 6编译环境搭建 (Marshmallow)
  2. 通过 Informix 系统表监控和优化数据库
  3. 设置让ASP.NET管道接收所有类型的请求
  4. Android 核心分析 之七Service深入分析
  5. 【Asp.Net MVC】Avoid Mass Assignment in ASP.NET MVC
  6. RSA使用 常识
  7. MySQL - 复制数据表
  8. vim 中Ctags的安装和使用
  9. sqlserver查询所有表的行数的sql语句
  10. cordova插件开发-1
  11. 解析STL中典型的内存分配
  12. Oracle删除控制文件恢复
  13. xcode修改代码目录结构出现clang:error:nosuchfileordirectory解决方法
  14. pip的安装问题
  15. L2-2 小字辈 (25 分)
  16. python经典书籍必看:流畅的Python
  17. project6 PIT游戏
  18. Centos6.5---samba文件共享服务配置(一)
  19. 《Java编程的逻辑》 - 文章列表
  20. SQLServer 索引重建

热门文章

  1. chrome headless
  2. ARC073D Simple Knapsack
  3. Linux shell实现阳历转农历
  4. java全栈day09----继承 抽象类
  5. docker安装oracle
  6. 容器编排之Kubernetes1.7.6安装与配置
  7. 微信小程序小结(5) -- 常用语法
  8. THINKPHP 框架的模板技术
  9. 解决vue-cli相对路径问题 about css assert path ,two Solution(css路径的问题解决方案) #179
  10. P2105 K皇后