https://github.com/spring-projects/spring-framework/blob/5.0.x/spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java
https://github.com/spring-projects/spring-framework/blob/5.0.x/spring-tx/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java
根据以上两个源码
AbstractPlatformTransactionManager.java 和 TransactionSynchronizationManager.java
总结Spring事务失效的原因:
类别 根本原因 典型场景
线程问题 事务上下文绑定在 ThreadLocal,但业务操作不在同一线程 多线程/异步操作
代理问题 @Transactional 方法未被 AOP 拦截 self-invocation、非 public 方法
传播行为 getTransaction 根据传播策略决定是否创建事务 不匹配的 REQUIRED/REQUIRES_NEW/SUPPORTS
底层资源 数据源自动提交、事务管理器未配置正确 autoCommit=true,DataSource 与 TM 不匹配
异常策略 Spring 默认只对 RuntimeException 回滚 捕获或抛出 checked exception
核心归因:Spring 事务依赖 ThreadLocal + 代理拦截,只要这两者失效,事务就失效。
其他因素(传播、异常、数据源)都是“间接原因”。
好了好了,根据以上的源码分析和 Spring 事务管理机制,可以总结出 Spring 事务失效的根本原因,核心其实都和 事务上下文无法正确绑定到当前线程 有关。下面详细分析:
1️⃣ Spring 事务核心机制回顾
Spring 的事务管理主要依赖:
-
AbstractPlatformTransactionManager:事务模板,负责完整流程控制(begin → commit/rollback)。
-
getTransaction():判断是否已有事务、处理传播行为、启动新事务。 -
commit():检查回滚标记、触发回调、执行平台特定提交。 -
rollback():事务回滚。
-
-
TransactionSynchronizationManager:
-
核心是 ThreadLocal 存储事务相关资源(比如 JDBC Connection)。
-
bindResource()/unbindResource():将事务资源绑定到当前线程。 -
isActualTransactionActive():判断当前线程是否有活动事务。
-
-
AOP / @Transactional:
-
使用
TransactionInterceptor拦截业务方法。 -
拦截器内部调用
PlatformTransactionManager.getTransaction()。 -
方法执行完成后调用
commit()或rollback()。
-
2️⃣ 事务失效的典型根本原因
(1) 事务资源没有绑定到线程
-
Spring 使用 ThreadLocal 管理事务资源。
-
如果业务逻辑没有在同一个线程中执行,ThreadLocal 就取不到事务上下文。
-
典型场景:
-
多线程调用:在 @Transactional 方法中开启新线程执行数据库操作。
-
异步调用:使用
@Async或ExecutorService执行数据库操作。
-
-
结果:新的线程中
TransactionSynchronizationManager.isActualTransactionActive()返回 false,事务失效。
(2) 事务方法没有被 AOP 代理拦截
-
Spring 的 @Transactional 是 基于代理的,默认:
-
JDK 动态代理:只能拦截接口方法。
-
CGLIB 代理:拦截类方法。
-
-
失效场景:
-
同类内部调用(self-invocation):
class Service { @Transactional void methodA() { ... } void methodB() { methodA(); // self-invocation, @Transactional 不会生效 } } -
非 public 方法(默认 Spring 事务只对 public 方法生效)。
-
(3) 事务传播行为不匹配
-
如果传播行为设置不当,也可能导致事务失效:
-
比如方法使用
REQUIRES_NEW,但调用方没有事务。 -
如果方法使用
SUPPORTS,但调用方没有事务,内部就不会开启新事务。
-
-
本质:
AbstractPlatformTransactionManager.getTransaction()根据传播行为决定是否创建新事务,传播策略不匹配就不会开启事务。
(4) 数据源或事务管理器配置问题
-
事务只是 逻辑封装,必须依赖正确的底层资源:
-
使用的
DataSource是非 XA、自动提交被开启 (autoCommit=true)。 -
PlatformTransactionManager未正确注入到代理或业务层。
-
-
这种情况下,即使
getTransaction()被调用,底层数据库也可能在每条 SQL 自动提交,导致“事务失效”。
(5) 异常处理不当
-
默认 Spring 事务只对 RuntimeException / Error 回滚。
-
如果捕获异常后吞掉,或者抛出 检查型异常(checked exception):
-
commit()会认为事务正常提交。 -
结果业务回滚预期不生效。
-
3️⃣ 总结根本原因
| 类别 | 根本原因 | 典型场景 |
|---|---|---|
| 线程问题 | 事务上下文绑定在 ThreadLocal,但业务操作不在同一线程 | 多线程/异步操作 |
| 代理问题 | @Transactional 方法未被 AOP 拦截 | self-invocation、非 public 方法 |
| 传播行为 | getTransaction 根据传播策略决定是否创建事务 | 不匹配的 REQUIRED/REQUIRES_NEW/SUPPORTS |
| 底层资源 | 数据源自动提交、事务管理器未配置正确 | autoCommit=true,DataSource 与 TM 不匹配 |
| 异常策略 | Spring 默认只对 RuntimeException 回滚 | 捕获或抛出 checked exception |
核心归因:Spring 事务依赖 ThreadLocal + 代理拦截,只要这两者失效,事务就失效。其他因素(传播、异常、数据源)都是“间接原因”。
1547

被折叠的 条评论
为什么被折叠?



