事務失效場景1:方法非public修飾
原因
Spring事務基于動態代理(AOP)實現,非public方法無法被代理攔截,導致事務失效。
代碼示例
@Service
public class OrderService {@Transactionalprivate void createOrder() { // 非public方法// 業務邏輯}
}
解決方案
- 將方法改為
public
修飾。 - 若需限制方法訪問權限,可通過編程式事務(
TransactionTemplate
)實現。
事務失效場景2:自調用問題
原因
同類中方法A調用方法B(帶@Transactional
),由于代理機制失效,事務不生效。
代碼示例
@Service
public class UserService {public void updateUser() {this.saveUser(); // 自調用}@Transactionalpublic void saveUser() {// 數據庫操作}
}
解決方案
- 將事務方法拆分到另一個類中,通過注入調用。
- 使用
AopContext.currentProxy()
獲取代理對象(需開啟exposeProxy
)。
事務失效場景3:異常類型未被捕獲
原因
默認僅對RuntimeException
和Error
回滾,若拋出其他異常(如IOException
)且未配置rollbackFor
,事務不會回滾。
代碼示例
@Transactional
public void processData() throws IOException {// 拋出IOExceptionthrow new IOException("文件異常");
}
解決方案
- 明確指定回滾異常類型:
@Transactional(rollbackFor = Exception.class)
事務失效場景4:事務傳播行為配置錯誤
原因
例如REQUIRES_NEW
嵌套使用時,內層事務失敗可能不影響外層事務。
代碼示例
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {innerMethod(); // 內層事務獨立提交
}@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {// 操作失敗但outerMethod繼續執行
}
解決方案
- 根據業務需求調整傳播行為,如改為
REQUIRED
。 - 避免過度嵌套事務。
事務失效場景5:多數據源未指定事務管理器
原因
多數據源環境下未明確指定transactionManager
,導致事務綁定到默認管理器。
代碼示例
@Transactional // 默認使用primary事務管理器
public void saveToSecondaryDB() {// 操作secondary數據源
}
解決方案
- 注解中指定事務管理器:
@Transactional("secondaryTransactionManager")
事務失效場景6:手動捕獲異常未拋出
原因
捕獲異常后未重新拋出,事務攔截器無法觸發回滾。
代碼示例
@Transactional
public void updateOrder() {try {// 數據庫操作} catch (Exception e) {log.error("錯誤", e); // 未拋出異常}
}
解決方案
- 在
catch
塊中拋出RuntimeException
。 - 或使用
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
手動回滾。
事務失效場景7:非事務方法調用事務方法
原因
若父類方法未開啟事務,調用子類@Transactional
方法時,代理失效。
代碼示例
public class BaseService {public void execute() {save(); // 事務失效}@Transactionalpublic void save() {}
}
解決方案
- 將事務注解添加到父類方法。
- 避免通過繼承層級調用事務方法。
總結
- 檢查方法修飾符和代理機制。
- 確保異常類型和傳播行為匹配業務需求。
- 多數據源需顯式指定事務管理器。
- 優先通過設計規避自調用問題。