@Transactional事务失效的关键是调用未经过Spring代理对象,必须通过其他Bean调用而非this/new、方法须为public非final/static、异常需为RuntimeException或显式rollbackFor、且数据库引擎和线程环境须支持事务。

排查 Spring @Transactional 事务失效,关键不是盲目检查配置,而是顺着“代理是否被调用”这条主线快速定位。事务注解本身不执行任何逻辑,它依赖 Spring AOP 生成的代理对象来织入事务拦截器。只要调用没经过代理,事务就静默失效——不报错、不打日志、只留脏数据。
看调用路径:是不是通过 this 或 new 调用?
这是最常见也最隐蔽的问题。同类中方法 A 直接调用方法 B(this.methodB()),或在方法内 new ServiceImpl() 后调用,都会绕过代理对象。
- 检查所有对带
@Transactional方法的调用方:是来自其他 Spring Bean(如 Controller、其他 Service)?还是本类内部? - 如果是本类调用,必须改为通过注入的代理 Bean 调用(例如注入自身:
@Autowired private OrderService self;,再用self.updateInventory()) - 避免在事务方法里 new 对象调用事务方法,那相当于完全脱离 Spring 容器管理
看方法定义:是不是 public?有没有 final/static?
Spring 的 JDK 动态代理和 CGLIB 代理都要求目标方法可被增强。非 public、final、static 方法无法被代理,事务拦截器根本不会触发。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 确认方法修饰符是 public(Spring 5.0+ 会对非 public 报错,旧版本则静默忽略)
- 移除
final和static修饰——它们阻止子类重写,而代理正是靠继承或接口实现来插入逻辑 - 不要把
@Transactional加在 private 工具方法上,即使它被 public 方法调用,也不会生效
看异常处理:有没有被 catch 吞掉?抛的是什么类型?
事务回滚默认只响应 RuntimeException 和 Error。Checked Exception(如 IOException、SQLException)不会触发回滚,除非显式声明 rollbackFor;而如果异常被 try-catch 捕获且未重新抛出,事务也会当作“正常完成”提交。
立即学习“Java免费学习笔记(深入)”;
- 检查方法中是否用了
try-catch,捕获后仅打印日志或吞掉异常 → 必须throw e或throw new RuntimeException(e) - 若业务抛的是自定义 Exception(继承
Exception),务必加上@Transactional(rollbackFor = Exception.class) - 注意:
catch (Exception e) { log.error(...); return; }这种写法会让事务提前提交
看运行环境:数据库、线程、容器托管是否到位?
事务生效还依赖外部条件。哪怕代码完全正确,底层环境不支持,事务照样无效。
- 确认数据库表引擎支持事务(MySQL 避免 MyISAM,应使用 InnoDB)
- 检查该 Service 类是否被 Spring 管理(类上有
@Service/@Component,且包路径被@ComponentScan扫描到) - 多线程场景下(如
@Async或手动 new Thread),新线程拿不到主线程绑定的事务上下文(ThreadLocal 中的 Connection)→ 事务失效 - 检查是否误配了
propagation,比如PROPAGATION_NOT_SUPPORTED会挂起当前事务,导致后续操作无事务保护

















