Spring 双层事务,我抛出的异常去哪了?
作者: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 双层事务,我抛出的异常去哪了?相关推荐
- Spring事务抛出Exception异常不回滚
今天有个业务逻辑流程为: 1.访客预约确认先更新预约状态为"预约确认" 2.调用http接口发短信.更新预约状态为"预约成功"等一系列操作 这里面有个问题,如果 ...
- controller的异常处理以及service层的事务控制___controller层 trycatch不影响service层抛出的异常
controller的异常处理以及service层的事务控制 最近写代码涉及到一些事务,上午终于把代码给理顺了,之前不太清楚在哪里做异常处理,导致代码遍地try-catch,相当难看. 还是基于con ...
- Spring捕获AOP抛出的异常
Spring捕获AOP抛出的异常 背景 解决过程 最初方案 失败探索 添加AOP 继承SDK的AOP类 修改AOP生效条件 最终解决方案--BeanPostProcessor 总结 背景 在最近开发中 ...
- Spring-AOP @AspectJ进阶之绑定抛出的异常
文章目录 概述 实例 总结 概述 和通过切点函数绑定连接点信息不同,连接点抛出的异常必须使用AfterThrowing注解的throwing成员进行绑定 实例 代码已托管到Github-> ht ...
- 获取线程中抛出的异常信息
1 ScheduledExecutorService service = Executors.newScheduledThreadPool(10); 2 // 从现在开始delay毫秒之后,每隔一天执 ...
- springboot springmvc 抛出全局异常解决方法
springboot springmvc 抛出全局异常解决方法 参考文章: (1)springboot springmvc 抛出全局异常解决方法 (2)https://www.cnblogs.com/ ...
- Java中主线程如何捕获子线程抛出的异常
Java中主线程如何捕获子线程抛出的异常 参考文章: (1)Java中主线程如何捕获子线程抛出的异常 (2)https://www.cnblogs.com/jpfss/p/10272885.html ...
- druid抛出的异常------javax.management.InstanceAlreadyExistsException引发的一系列探索
druid抛出的异常------javax.management.InstanceAlreadyExistsException引发的一系列探索 参考文章: (1)druid抛出的异常------jav ...
- 第8集析构函数中抛出的异常
前两篇文章讨论了对象在构造过程中(构造函数)和运行过程中(成员函数)出现异常时的处理情况,本文将讨论最后一种情况,当异常发生在对象的析构销毁过程中时,又会有什么不同呢?主人公阿愚在此可以非常有把握地告 ...
- 第7集 构造函数中抛出的异常
上一篇文章简单讨论了一下对象的成员函数抛出异常时的处理情况.本文中将继续讨论当在构造函数中抛出异常时,程序的执行情况又如何?这有点复杂呀!而且主人公阿愚还觉得这蛮有点意思! 构造函数中抛出的异常 1. ...
最新文章
- c语言ctype中替换查找字符,c – std :: ctype是否总是按“C”语言环境对字符进行分类?...
- 让linux启动更快的方法
- 理解浏览器允许的并发请求资源数
- EUI库 - EXML
- 台式计算机桌面待机时间怎么调,如何设置电脑屏幕待机时间
- data stucture at the xuetang x
- axure7 地址选择_AxureRP8实战手册-案例7(形状:唯一选中项)
- 隐藏PHP扩展名-修改apache
- Oracle数据库日常管理之数据备份,恢复及迁移 (第五讲 )
- 微服务集成cas_Spring Cloud(四) Spring Cloud Security集成CAS (单点登录)对微服务认证...
- 江苏计算机等级考试试卷,江苏省计算机等级考试程序设计 试卷.docx
- 【转载】美国煤层气发展史
- php 用什么缓存最好,在PHP中缓存中/大型数据集的一些最好的工具/策略是什么?...
- (Sublime Text 3)完美替换 GAMS 难用的编辑器
- Python爬虫番外篇之关于登录
- ssas连接mysql_BI-SSAS简介篇
- numpy数组某一行求和 python_【Python】No.2 Numpy和Matplotlib初体验
- html中首行缩进两个字符
- Unity 之 发布 WebGl 遇到的问题
- C++实现二叉树同构
热门文章
- EasyRecovery如何添加XML头文件标识
- 音乐艺考生如何提高视唱练耳技巧
- Activiti5.22:删除工作流引擎自动创建的外键约束
- sql server 提取汉字/数字/字母的方法
- OpenResty Redis 安装部署测试SET GET功能
- 483. Smallest Good Base
- POI 读取 Excel 文件(2003版本与2007版本的差异之处)
- IpV6 linux RedHat5
- 「leetcode」106.从中序与后序遍历序列构造二叉树 105. 从前序与中序遍历序列构造二叉树 (详解)
- 类 ACDSee图像浏览工具Lyn for Mac