spring事务因自调用失效,本质是未走代理对象;防范需确保@transaction方法通过代理执行:拆至独立service、注入自身bean(加@lazy)、或启用aopcontext获取当前代理;另须方法为public且异常向外抛出。

Spring 事务因内部方法调用(即自调用)失效,本质是代理机制没被触发——this.saveOrder() 调用的是原始对象,不是 Spring 创建的代理对象,事务切面根本没机会介入。防范的关键,是确保带 @Transactional 的方法**一定通过代理对象执行**。
把事务方法拆到另一个 Service 类
最清晰、最符合分层设计原则的做法。让事务逻辑归属独立组件,天然走代理调用路径。
- 新建
OrderPersistenceService,把@Transactional public void saveOrder()移过去 - 在原
OrderService中注入它:@Autowired private OrderPersistenceService persistenceService; - 调用时写
persistenceService.saveOrder(),Spring 自动使用代理对象
在当前类中注入自身 Bean
不改结构也能快速修复,适合临时调整或轻量场景。注意必须加 @Lazy 避免循环依赖。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在类内声明:
@Autowired @Lazy private OrderService self; - 把
this.saveOrder()改成self.saveOrder() - 确保类本身是 Spring 管理的 Bean(如加了
@Service)
启用 AopContext 并获取当前代理
适用于无法修改类注入关系的场景(如已有复杂依赖),但需额外配置且侵入性强。
- 启动类加注解:
@EnableAspectJAutoProxy(exposeProxy = true) - 方法内调用写成:
((OrderService) AopContext.currentProxy()).saveOrder() - 注意:仅在当前线程有效,且不能用于异步或新线程中
补充两个关键避坑点
光解决调用方式还不够,这两点常被忽略,却直接导致事务静默失效:
-
方法必须是 public:private/protected/default 方法上的
@Transactional会被 Spring 完全忽略(AOP 拦截器不生效) -
异常要往外抛:事务默认只对 unchecked 异常(
RuntimeException及其子类)回滚;若捕获了异常又没重新抛出,事务会正常提交
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










