從啟動失敗、循環依賴到事務失效與 CORS 跨域,覆蓋 Spring Boot 開發中最常踩到的坑,每條都附根因分析與驗證解法。
啟動失敗、自動設定、Servlet 容器、Profile、打包
應用被當成 Web 應用卻找不到容器工廠,啟動即報 missing ServletWebServerFactory bean。
訪問接口見到白頁,提示 no explicit mapping for /error。多是請求沒匹配到 Controller,包結構或註解寫錯。
Spring Boot 2.6 預設改用 PathPatternParser,springfox 不兼容,啟動即拋 nested NPE。
升級到 Spring Boot 3 最低要 Java 17,javax.* 全部換成 jakarta.*,Spring Security 設定也需重寫。
內嵌 Web 服務器預設綁 8080,一旦被其他進程佔用就啟動失敗。先定位佔用進程,再改端口或釋放。
Bean 缺失/衝突、循環依賴、@ComponentScan
訪問接口見到白頁,提示 no explicit mapping for /error。多是請求沒匹配到 Controller,包結構或註解寫錯。
注入時報 NoSuchBeanDefinitionException,多是類不在 @ComponentScan 範圍內,跨包 Bean 漏掉。
Spring Boot 2.6 起預設禁止 Bean 循環依賴,升級後啟動失敗,可重構或開 allow-circular-references。
DataSource、JPA、連接池、Flyway、MyBatis
Flyway 啟動校驗失敗,報 Migration checksum mismatch,已執行過的遷移腳本被改過,本地與庫裡 checksum 對不上。
引入 spring-boot-starter-data-jpa 卻沒配連接,自動設定強制裝配 DataSource 又找不到 url。
運行時冒 HikariPool Connection is not available,多數是連接借出後沒歸還,直到超時。
查 N 個父實體再遍歷訪問關聯會觸發 N 條額外查詢,用 JOIN FETCH、@EntityGraph 或 @BatchSize 優化。
@Transactional 失效、傳播、緩存
@Transactional 標在 private 方法上既不報錯也不生效,代理只能攔截穿過代理的外部調用,private 方法無法被覆蓋。
Spring Boot 預設用 CGLIB 代理,final 類或方法無法被子類化,註解靜默失效或拋 AopConfigException。
@Transactional 預設只回滾 RuntimeException 和 Error,拋受檢例外時事務照常提交,需配 rollbackFor。
NESTED 依賴數據庫保存點實現部分回滾,JPA 方言不支持 savepoint 時直接拋 TransactionSystemException。
事務上下文用 ThreadLocal 綁定當前執行緒,new Thread 或 @Async 裡的寫操作拿不到事務,獨立提交且不跟隨外層回滾。
容器裡找不到名為 transactionManager 的 Bean 時,@Transactional 方法調用直接拋例外,多因自動裝配失效。
配多數據源後 @Transactional 按類型找事務管理器,多個候選就拋 NoUniqueBeanDefinitionException。
REQUIRES_NEW 掛起外層事務並開啟獨立新事務,內層一旦提交,外層回滾無法撤銷,產生髒數據。
Spring 只在例外穿過代理邊界時才回滾,事務方法內 try-catch 捕獲例外未重新拋出,代理感知不到,事務照常提交。
內層事務例外被外層 catch 吞掉後繼續提交,但物理事務已標記 rollback-only,提交時拋 UnexpectedRollbackException。
同類裡用 this 調用帶 @Async 或 @Transactional 的方法,註解會靜默失效,可抽 Bean、注入自身代理或走 AopContext。
Controller、參數校驗、Jackson、CORS、例外處理
RestTemplate/WebClient、超時、連接
@Async、定時任務、消息隊列
容器裡找不到名為 transactionManager 的 Bean 時,@Transactional 方法調用直接拋例外,多因自動裝配失效。
配多數據源後 @Transactional 按類型找事務管理器,多個候選就拋 NoUniqueBeanDefinitionException。
Spring Boot 2.1 起預設禁用同名 Bean 覆蓋,業務程式碼與第三方 Starter 註冊同名 Bean 時拋該例外。
profile 缺失或 spring.config.import 路徑無效時拋 ConfigDataLocationNotFoundException。
@Transactional 標在 private 方法上既不報錯也不生效,代理只能攔截穿過代理的外部調用,private 方法無法被覆蓋。
Spring Boot 預設用 CGLIB 代理,final 類或方法無法被子類化,註解靜默失效或拋 AopConfigException。
@Transactional 預設只回滾 RuntimeException 和 Error,拋受檢例外時事務照常提交,需配 rollbackFor。
NESTED 依賴數據庫保存點實現部分回滾,JPA 方言不支持 savepoint 時直接拋 TransactionSystemException。
REQUIRES_NEW 掛起外層事務並開啟獨立新事務,內層一旦提交,外層回滾無法撤銷,產生髒數據。
Spring 只在例外穿過代理邊界時才回滾,事務方法內 try-catch 捕獲例外未重新拋出,代理感知不到,事務照常提交。
內層事務例外被外層 catch 吞掉後繼續提交,但物理事務已標記 rollback-only,提交時拋 UnexpectedRollbackException。
Spring Boot 2.1 起預設禁用同名 Bean 覆蓋,業務程式碼與第三方 Starter 註冊同名 Bean 時拋該例外。