Spring声明式事务失效的本质是调用未经过代理对象,导致TransactionInterceptor拦截逻辑未触发。常见场景包括:1.方法非public,源码中computeTransactionAttribute直接返回null;2.同类内部自调用,绕过代理;3.异常被吞或非RuntimeException未配置rollbackFor;4.数据库引擎不支持事务(如MyISAM);5.类未被Spring管理、方法为final/static、多线程调用、传播行为配置错误。

Spring 声明式事务(@Transactional)失效,本质是事务拦截逻辑没被触发——方法没经过 Spring 生成的代理对象执行。只要调用绕过了代理,或者事务上下文无法建立/传播,事务就形同虚设。下面这几种情况最常见、最容易踩坑。
方法不是 public
Spring AOP 默认只对 public 方法做代理增强。如果把 @Transactional 加在 private、protected 或包级私有方法上,代理根本不会拦截它。
- 源码层面,
AbstractFallbackTransactionAttributeSource.computeTransactionAttribute()明确判断:!Modifier.isPublic(method.getModifiers())就直接返回null,事务配置被忽略 - 解决办法很简单:统一改成
public方法
同一个类里自己调自己(内部调用)
这是开发中最高频的失效场景。比如一个 service 类里,methodA() 没加注解,但里面写了 this.methodB(),而 methodB() 加了 @Transactional——此时事务不生效。
- 原因:调用的是当前对象(
this)的原生方法,没走 Spring 代理对象,AOP 完全没介入 - 修复方式有三种:
• 把methodB拆到另一个@Service类中
• 在当前类注入自身代理:@Autowired private UserService self;,然后用self.methodB()
• 启用AopContext.currentProxy()(需开启expose-proxy=true配置)
异常被吞掉或类型不匹配
事务回滚依赖 Spring 捕获到“该回滚的异常”。两种典型错误:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
-
try-catch 吞掉异常:方法里
catch了异常但没重新抛出,也没手动标记回滚,事务就静默提交了 -
抛出的异常不触发回滚:默认只对
RuntimeException和Error回滚;如果业务抛的是IOException这类受检异常,必须显式写@Transactional(rollbackFor = Exception.class) - 补救方式:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()可在 catch 块中强制回滚
数据库引擎不支持事务
再完美的 Java 层事务控制,也架不住底层存储不认账。比如 MySQL 的 MyISAM 引擎完全不支持事务,所有 @Transactional 都无效。
- 检查表引擎:
SHOW CREATE TABLE user;看ENGINE=InnoDB是否存在 - InnoDB 是默认且推荐的事务型引擎;MyISAM、Memory 等都不行
- 建表时务必指定:
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
其他关键失效点
还有几个容易被忽略但影响严重的场景:
-
类没被 Spring 管理:没加
@Service/@Component,Spring 根本不会为它生成代理对象 - final 或 static 方法:代理无法重写 final 方法;static 方法属于类级别,和代理实例无关
-
多线程或异步调用:新线程拿不到主线程绑定的
TransactionSynchronizationManager,事务上下文丢失 -
传播行为配置不当:比如用了
PROPAGATION_NOT_SUPPORTED,会挂起当前事务,实际不参与事务管理

















