news 2026/10/28 1:34:36

@Transactional事务问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@Transactional事务问题

文章目录

  • 前言
  • 一、try/catch 里把异常“吃掉了,事务不会回滚
  • 二、方法抛出 Checked Exception 且未配置 rollbackFor,事务不会回滚
  • 三:@Transactional 在同类方法调用会失效
  • 四:private 方法导致事务失效
  • 总结

前言

Spring事务默认只对 RuntimeException 和 Error 回滚,对 Checked Exception 不回滚;如果方法抛出 Checked Exception 且未配置 rollbackFor,事务会被正常提交。
Spring事务只在“代理对象调用方法时”生效,类内部 self-invocation(自调用)会绕过代理。


一、try/catch 里把异常“吃掉了,事务不会回滚

例子:

@Transactional @GetMapping("/test1")public voidcreate(){try{orderMapper.insert(new order(1L,1L));// 模拟异常 int a=1/0;}catch(Exception e){System.out.println("异常被捕获了:"+ e.getMessage());}}

解决:
1.直接不 catch

@Transactional public voidcreate(){orderMapper.insert(new order(1L,1L));int a=1/0;// 自动回滚}

2.重新抛出异常

@Transactional public voidcreate(){try{orderMapper.insert(new order(1L,1L));int a=1/0;}catch(Exception e){System.out.println("记录日志");throw new RuntimeException(e);// ⭐关键:必须抛出去}}

3.手动标记回滚

@Transactional public voidcreate(){try{orderMapper.insert(new order(1L,1L));int a=1/0;}catch(Exception e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}}

二、方法抛出 Checked Exception 且未配置 rollbackFor,事务不会回滚

例子:

@Transactional public void test()throws Exception{throw new Exception("编译时异常");}

❗关键原因

Spring 的逻辑是:

“我只会对 RuntimeException 感兴趣”

你的 Exception 是:

Checked Exception → Spring 默认忽略回滚

解决:
方案1:强制所有异常都回滚(推荐)

@Transactional(rollbackFor=Exception.class)public void test()throws Exception{throw new Exception("库存不足");}

方案2:统一用 RuntimeException

@Transactional public voidtest(){throw new RuntimeException("库存不足");}

三:@Transactional 在同类方法调用会失效

例子:

@Service public class OrderService{public voidcreateOrder(){insertOrder();// ❌ 同类调用}@Transactional public voidinsertOrder(){orderMapper.insert(...);int a=1/0;// 期待回滚}}

实际发生什么?

createOrder()→ 直接调用 insertOrder()❌ 没经过 Spring 代理 ❌ @Transactional 不生效

Spring事务基于AOP代理实现,仅在通过代理对象调用方法时生效;同类内部方法调用属于 self-invocation,不会经过代理,因此事务不会生效。

正确解决方案(重点)
✔ 方案1:拆服务(最推荐)

@Service public class OrderService{@Autowired private OrderTxService orderTxService;public voidcreateOrder(){orderTxService.insertOrder();}}@Service public class OrderTxService{@Transactional public voidinsertOrder(){orderMapper.insert(...);}}

方案2:通过代理调用自己(不推荐但可用)

@Autowired private ApplicationContext context;public voidcreateOrder(){OrderService proxy=context.getBean(OrderService.class);proxy.insertOrder();// ✔ 走代理}

四:private 方法导致事务失效

@Transactional private voidb(){}

❗原因

Spring AOP 无法代理 private 方法 只能代理 public/protected

总结

Spring 的声明式事务基于 AOP 实现。@Transactional 只是事务声明,Spring 会通过 JDK 动态代理或 CGLIB 为目标 Bean 创建代理对象。方法调用时先进入事务拦截器,由事务拦截器负责开启事务、提交事务和回滚事务。因此事务能否生效的关键在于是否经过代理对象,这也是同类调用、private 方法、final 方法等场景事务失效的根本原因。

面试生产环境中事务怎么使用?

1.统一配置 rollbackFor=Exception.class2.非核心业务拆解,用异步保证一致性3.统一异常体系:继承RuntimeException重写异常类4.事前压测

@作者:加辣椒了吗?
简介:憨批大学生一枚,喜欢在博客上记录自己的学习心得,也希望能够帮助到你们!
我在「辣椒微创」有更详细的案例和工具,你应该用得上!(主页有指路)
🚀 【创业项目】:副业灵感、轻资产玩法、互联网创收思路
📦 【资源分享】:PPT、音效、模板、字体、插件等创作者工具合集
🔧 【软件下载】:精选高效、靠谱的生产力工具及安装指南
💻 【编程开发】:编程学习资源、项目源码、开发工具、实战案例
🛒 【薅羊毛】:精选各种优惠折扣、平台补贴信息,帮你省钱放大收益。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:32:30

c++进阶之多态

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:32:07

2000-2024年 地级市-城乡居民社保相关数据数据(xlsx)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:31:45

等保2.0定级备案全流程:从定级到差距分析,附6份可套用模板

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:30:12

wireshark抓包的必学技巧

1.过滤器用好了,信息量大减半! 抓包容易,分析难,一大堆数据包扑面而来,如何迅速找到关键数据? 直接在 Display Filter 输入ip.addr192.168.1.1 只显示与192.168.1.1相关的流量。过滤 HTTP流量:http只看TCP三次握手:tcp.flags.syn…

作者头像 李华