@Transactional默认按名称transactionManager查找事务管理器 Bean。只配了数据源却把事务自动配置 exclude 掉、或自动装配根本没触发,就会抛NoSuchBeanDefinitionException: No bean named 'transactionManager' available——这是装配期就爆掉的硬报错,不是静默失效。
Issue & Env(案发现场与环境)
- JDK 版本:OpenJDK 17 / 21
- Spring Boot 版本:2.7.x / 3.x
- 依赖场景:使用 MyBatis / JDBC,或自定义数据源配置类但未注册配套事务管理器。
- 触发背景:应用启动一切正常,但在接收到第一个进入
@Transactional标注方法的业务请求时,系统直接抛出异常并中断请求处理。
Spring Boot 的声明式事务依赖一个 PlatformTransactionManager Bean。绝大多数项目不需要手动定义它,因为 Boot 提供了自动装配:
- 用 JDBC / MyBatis 时,
DataSourceTransactionManagerAutoConfiguration自动注册DataSourceTransactionManager; - 用 JPA 时,
JpaTransactionManagerAutoConfiguration自动注册JpaTransactionManager。
这些自动装配都有条件:类路径上要有对应依赖、容器里有 DataSource Bean、且没有被 exclude。一旦条件不满足或被手动排除,事务管理器就不会被注册。
StackTrace(堆栈日志)
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'transactionManager' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1324)
at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:507)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
关键特征:错误不在启动阶段,而是第一个事务方法调用时爆发,且异常栈里一定有 TransactionAspectSupport.determineTransactionManager。
Reproduce(复现代码)
启动类或配置类中显式排除了事务自动装配类,或只声明了数据源未声明事务管理器:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
// 复现:人为排除了 DataSourceTransactionManagerAutoConfiguration
@SpringBootApplication(exclude = DataSourceTransactionManagerAutoConfiguration.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
业务 Service 正常使用 @Transactional:
package com.example.demo.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Transactional
public void createOrder() {
// 任何数据库操作,进入该方法即刻抛出 NoSuchBeanDefinitionException
}
}
Root Cause(根因分析)
- Spring 事务切面的解析机制:当切面拦截到
@Transactional方法时,TransactionAspectSupport.determineTransactionManager会先尝试通过名称(默认transactionManager)获取PlatformTransactionManager。若注解上未指定 qualifier,Spring 会从容器中寻找唯一的事务管理器。 - 自动装配失效的三大诱因:
- 线索 1:主动 exclude。在
@SpringBootApplication或配置中误将DataSourceTransactionManagerAutoConfiguration.class加入了 exclude 列表。 - 线索 2:自定义数据源未注册配套事务管理器。团队自定义了多数据源或公共
DataConfig,显式声明了DataSourceBean,使 Spring Boot 默认的自动化数据源与事务管理器配置全面退让,但开发者未手动补上@Bean PlatformTransactionManager。 - 线索 3:缺少依赖。仅引入了第三方连接池但缺少
spring-boot-starter-jdbc或spring-boot-starter-data-jpa,导致自动装配条件ConditionOnClass无法达成。
- 线索 1:主动 exclude。在
可用以下命令快速排查是否存在 exclude 或检查条件评估报告:
grep -rn "exclude.*TransactionManager\|excludeName.*TransactionManager" src/main/java
java -jar app.jar --debug | grep -A2 "DataSourceTransactionManagerAutoConfiguration"
The Fix(解决方案)
方案 A(推荐):恢复自动装配,不手动管理
去掉对事务自动配置的 exclude,确保 spring-boot-starter-jdbc(或 spring-boot-starter-data-jpa)在依赖里,让 Boot 自动注册事务管理器:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
方案 B:手动补装配(多数据源 / 定制场景)
在多数据源或定制配置类中,补齐 PlatformTransactionManager Bean 定义:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
方案 C:显式指定事务管理器名称
如果容器里有事务管理器但不叫 transactionManager(例如叫 txManager),在 @Transactional 上显式指定:
@Transactional(transactionManager = "txManager")