@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")