作者:AMOS0626
来源:my.oschina.net/AmosWang/blog/4773386

系统 A 调用系统 B 执行数据同步,系统 B 返回了错误提示,系统 A 需要将前边保存的回滚掉,同时把错误信息向上抛。

大致代码如下

@Service("noteService")
public class NoteServiceImpl implements NoteService {@Resourceprivate SearchService searchService;@Transactional(rollbackFor = Throwable.class)@Overridepublic CommonResponse<NoteEntity> save(NoteEntity note) {// 一系列 DB 操作try {searchService.sync(note);} catch (Exception e) {e.printStackTrace();}return CommonResponse.success(entity);}}@Service("searchService")
public class SearchServiceImpl implements SearchService {@Transactional(rollbackFor = Throwable.class)@Overridepublic void sync(NoteEntity note) {// 一系列 DB 操作throw new RuntimeException("同步异常! [XXX]");}}@SpringBootTest
public class NoteTests {@Resourceprivate NoteService noteService;@Testpublic void saveNote() {NoteEntity entity = new NoteEntity();entity.setTitle("念奴娇赤壁怀古");entity.setContent("大江东去,浪淘尽,千古风流人物。故垒西边,人道是:三国周郎赤壁。。。");entity.setTags("苏轼,宋代");entity.setCategory("苏轼诗词");try {noteService.save(entity);} catch (Exception e) {e.printStackTrace();// FIXME 我想在这里拿到的是 同步异常! [XXX]// FIXME 但是这里拿到的是 Transaction silently rolled back because it has been marked as rollback-onlySystem.out.println(">>>>>>>>>> " + e.getMessage());}}}

事出有因

代码历史久远,为何这样写已无从追溯。

纳闷了一会儿,看到双层事务,就想起了 Spring事务传播机制,前边理解得比较肤浅。Spring 系列面试题和答案我全部整理好了,请关注公众号互联网架构师,回复:2T。

没有特殊的配置,自然是走默认的事务传播机制了,也就是 Propagation.REQUIRED。

国际惯例,列出事务传播机制:

1、PROPAGATION_REQUIRED
当前没事务,则创建事务;存在事务,就加入该事务,这是最常用的设置。2、PROPAGATION_SUPPORTS
当前存在事务,就加入事务,当前不存在事务,就以非事务方式执行。3、PROPAGATION_MANDATORY
当前存在事务,就加入事务;当前不存在事务,就抛出异常。4、PROPAGATION_REQUIRES_NEW
无条件创建新事务。5、PROPAGATION_NOT_SUPPORTED
以非事务方式执行,如果当前存在事务,就将当前事务挂起。6、PROPAGATION_NEVER
以非事务方式运行,如果存在事务,就抛出异常。7、PROPAGATION_NESTED
开始执行事务前,先保存一个savepoint,当发生异常时,就回滚到savepoint;没有异常时,跟着外部事务一起提交或回滚。

具体原因

1、看了上边的事务传播机制,继续细化问题,内外层共用一个事务,内层抛出异常,会导致整个事务失败。

2、继续分析,外层逻辑进行了 try catch,就导致内层的异常无法继续向上抛出,外层事务会继续提交。

3、事务提交时,进行事务状态的判断,就发现这个事务是失败的,需要回滚,所以抛出了 Transaction silently rolled back because it has been marked as rollback-only 的异常。

另外,大家想学 Spring Boot 的看下这个仓库,太全了。

https://github.com/javastacks/spring-boot-best-practice

怎么解决?

银弹自然是没有的,根据业务场景选择合适的方案。

1、当前这种场景,直接把外层逻辑中的 try catch 去掉即可。异常直接向上抛,事务就不会继续提交,调用方拿到的就是一手的异常;

2、如果内层不是核心逻辑,记录个日志啥的,可以把内层事务配置为 @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW), 无论如何,都创建新的事务,外层事务不受内层事务影响。但是有个问题,外层事务失败了,内层事务还是把记录入库了,有可能产生脏数据;

3、如果外层事务失败了,内层事务也不能提交,那就可以使用 @Transactional(rollbackFor = Throwable.class, propagation = Propagation.NESTED)。注意:hibernate/jpa 不支持嵌套事务 NESTED,可用 JdbcTemplate 代替。

PS:如果觉得我的分享不错,欢迎大家随手点赞、在看。

大家一起在评论区聊聊呗~

关注微信公众号:互联网架构师,在后台回复:2T,可以获取我整理的教程,都是干货。

猜你喜欢

1、GitHub 标星 3.2w!史上最全技术人员面试手册!FackBoo发起和总结

2、如何才能成为优秀的架构师?

3、从零开始搭建创业公司后台技术栈

4、程序员一般可以从什么平台接私活?

5、37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6、滴滴业务中台构建实践,首次曝光

7、不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

8、15张图看懂瞎忙和高效的区别

9、2T架构师学习资料干货分享

Spring 双层事务,我抛出的异常去哪了?相关推荐

  1. Spring事务抛出Exception异常不回滚

    今天有个业务逻辑流程为: 1.访客预约确认先更新预约状态为"预约确认" 2.调用http接口发短信.更新预约状态为"预约成功"等一系列操作 这里面有个问题,如果 ...

  2. controller的异常处理以及service层的事务控制___controller层 trycatch不影响service层抛出的异常

    controller的异常处理以及service层的事务控制 最近写代码涉及到一些事务,上午终于把代码给理顺了,之前不太清楚在哪里做异常处理,导致代码遍地try-catch,相当难看. 还是基于con ...

  3. Spring捕获AOP抛出的异常

    Spring捕获AOP抛出的异常 背景 解决过程 最初方案 失败探索 添加AOP 继承SDK的AOP类 修改AOP生效条件 最终解决方案--BeanPostProcessor 总结 背景 在最近开发中 ...

  4. Spring-AOP @AspectJ进阶之绑定抛出的异常

    文章目录 概述 实例 总结 概述 和通过切点函数绑定连接点信息不同,连接点抛出的异常必须使用AfterThrowing注解的throwing成员进行绑定 实例 代码已托管到Github-> ht ...

  5. 获取线程中抛出的异常信息

    1 ScheduledExecutorService service = Executors.newScheduledThreadPool(10); 2 // 从现在开始delay毫秒之后,每隔一天执 ...

  6. springboot springmvc 抛出全局异常解决方法

    springboot springmvc 抛出全局异常解决方法 参考文章: (1)springboot springmvc 抛出全局异常解决方法 (2)https://www.cnblogs.com/ ...

  7. Java中主线程如何捕获子线程抛出的异常

    Java中主线程如何捕获子线程抛出的异常 参考文章: (1)Java中主线程如何捕获子线程抛出的异常 (2)https://www.cnblogs.com/jpfss/p/10272885.html ...

  8. druid抛出的异常------javax.management.InstanceAlreadyExistsException引发的一系列探索

    druid抛出的异常------javax.management.InstanceAlreadyExistsException引发的一系列探索 参考文章: (1)druid抛出的异常------jav ...

  9. 第8集析构函数中抛出的异常

    前两篇文章讨论了对象在构造过程中(构造函数)和运行过程中(成员函数)出现异常时的处理情况,本文将讨论最后一种情况,当异常发生在对象的析构销毁过程中时,又会有什么不同呢?主人公阿愚在此可以非常有把握地告 ...

  10. 第7集 构造函数中抛出的异常

    上一篇文章简单讨论了一下对象的成员函数抛出异常时的处理情况.本文中将继续讨论当在构造函数中抛出异常时,程序的执行情况又如何?这有点复杂呀!而且主人公阿愚还觉得这蛮有点意思! 构造函数中抛出的异常 1. ...

最新文章

  1. c语言ctype中替换查找字符,c – std :: ctype是否总是按“C”语言环境对字符进行分类?...
  2. 让linux启动更快的方法
  3. 理解浏览器允许的并发请求资源数
  4. EUI库 - EXML
  5. 台式计算机桌面待机时间怎么调,如何设置电脑屏幕待机时间
  6. data stucture at the xuetang x
  7. axure7 地址选择_AxureRP8实战手册-案例7(形状:唯一选中项)
  8. 隐藏PHP扩展名-修改apache
  9. Oracle数据库日常管理之数据备份,恢复及迁移 (第五讲 )
  10. 微服务集成cas_Spring Cloud(四) Spring Cloud Security集成CAS (单点登录)对微服务认证...
  11. 江苏计算机等级考试试卷,江苏省计算机等级考试程序设计 试卷.docx
  12. 【转载】美国煤层气发展史
  13. php 用什么缓存最好,在PHP中缓存中/大型数据集的一些最好的工具/策略是什么?...
  14. (Sublime Text 3)完美替换 GAMS 难用的编辑器
  15. Python爬虫番外篇之关于登录
  16. ssas连接mysql_BI-SSAS简介篇
  17. numpy数组某一行求和 python_【Python】No.2 Numpy和Matplotlib初体验
  18. html中首行缩进两个字符
  19. Unity 之 发布 WebGl 遇到的问题
  20. C++实现二叉树同构

热门文章

  1. EasyRecovery如何添加XML头文件标识
  2. 音乐艺考生如何提高视唱练耳技巧
  3. Activiti5.22:删除工作流引擎自动创建的外键约束
  4. sql server 提取汉字/数字/字母的方法
  5. OpenResty Redis 安装部署测试SET GET功能
  6. 483. Smallest Good Base
  7. POI 读取 Excel 文件(2003版本与2007版本的差异之处)
  8. IpV6 linux RedHat5
  9. 「leetcode」106.从中序与后序遍历序列构造二叉树 105. 从前序与中序遍历序列构造二叉树 (详解)
  10. 类 ACDSee图像浏览工具Lyn for Mac