首页 / 资讯中心 / 文章详情

@Transactional事务问题

@Transactional事务问题 ★ FEATURED ARTICLE
文章目录前言一、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 a1/0;}catch(Exception e){System.out.println(异常被捕获了 e.getMessage());}}解决1.直接不 catchTransactional public voidcreate(){orderMapper.insert(new order(1L,1L));int a1/0;// 自动回滚}2.重新抛出异常Transactional public voidcreate(){try{orderMapper.insert(new order(1L,1L));int a1/0;}catch(Exception e){System.out.println(记录日志);throw new RuntimeException(e);// ⭐关键必须抛出去}}3.手动标记回滚Transactional public voidcreate(){try{orderMapper.insert(new order(1L,1L));int a1/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(rollbackForException.class)public void test()throws Exception{throw new Exception(库存不足);}方案2统一用 RuntimeExceptionTransactional public voidtest(){throw new RuntimeException(库存不足);}三Transactional 在同类方法调用会失效例子Service public class OrderService{public voidcreateOrder(){insertOrder();// ❌ 同类调用}Transactional public voidinsertOrder(){orderMapper.insert(...);int a1/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 proxycontext.getBean(OrderService.class);proxy.insertOrder();// ✔ 走代理}四private 方法导致事务失效Transactional private voidb(){}❗原因Spring AOP 无法代理 private 方法 只能代理 public/protected总结Spring 的声明式事务基于 AOP 实现。Transactional 只是事务声明Spring 会通过 JDK 动态代理或 CGLIB 为目标 Bean 创建代理对象。方法调用时先进入事务拦截器由事务拦截器负责开启事务、提交事务和回滚事务。因此事务能否生效的关键在于是否经过代理对象这也是同类调用、private 方法、final 方法等场景事务失效的根本原因。面试生产环境中事务怎么使用1.统一配置 rollbackForException.class2.非核心业务拆解用异步保证一致性3.统一异常体系继承RuntimeException重写异常类4.事前压测作者加辣椒了吗简介憨批大学生一枚喜欢在博客上记录自己的学习心得也希望能够帮助到你们我在「辣椒微创」有更详细的案例和工具你应该用得上(主页有指路) 【创业项目】副业灵感、轻资产玩法、互联网创收思路 【资源分享】PPT、音效、模板、字体、插件等创作者工具合集 【软件下载】精选高效、靠谱的生产力工具及安装指南 【编程开发】编程学习资源、项目源码、开发工具、实战案例 【薅羊毛】精选各种优惠折扣、平台补贴信息帮你省钱放大收益。
阅读完成 · 觉得有帮助?
咨询建站