在日常工作中,經常使用@Transactional 注解進行事務的聲明,但如果發現事務未生效,可以從下面幾個方面進行排查。
常見失效場景總結
場景 | 原因 | 解決方案 |
---|---|---|
內部方法調用 | 繞過了Spring代理 | 注入自身或使用AopContext |
private方法 | AOP無法增強 | 改為public方法 |
final方法/類 | 無法被代理 | 移除final修飾符 |
非Spring管理 | 不是代理對象 | 確保Bean由Spring管理 |
異常被捕獲 | 異常未拋出到代理層 | 檢查異常處理邏輯 |
數據庫不支持 | 如MyISAM引擎 | 使用InnoDB等支持事務的引擎 |
1、配置事務管理器
在服務的啟動類,需要配置@EnableTransactionManagement,核心作用是啟用Spring的聲明式事務管理功能。
在Spring Boot中,通常不需要顯式添加@EnableTransactionManagement;但如果exclude = {DataSourceAutoConfiguration.class}
排除了DataSource自動配置,則需要顯式聲明
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) // 排除是由于項目需要,需要聲明多數據源
@EnableTransactionManagement // 激活事務管理
public class Application {// 啟用后,Spring會為帶有@Transactional的Bean創建代理
}
或者可以使用XML配置方式配置
<tx:annotation-driven transaction-manager="transactionManager"/>
2、代理機制生效
// ? 錯誤:內部方法調用,事務不生效
@Service
public class UserService {@Transactionalpublic void methodA() {// 直接調用內部方法,事務失效this.methodB();}@Transactionalpublic void methodB() {// 事務不會生效}
}// ? 正確:通過Spring代理調用
@Service
public class UserService {@Autowiredprivate UserService self; // 注入自己或通過ApplicationContext獲取@Transactionalpublic void methodA() {// 通過代理調用,事務生效self.methodB();}@Transactionalpublic void methodB() {// 事務生效}
}
3、異常類型匹配
@Transactional(rollbackFor = Exception.class)
public String createTask(ModelTaskDTO modelTaskDTO) throws TException, InterruptedException {// 所有異常都會回滾
}// 默認情況只回滾RuntimeException和Error
@Transactional // 只回滾RuntimeException
public void defaultRollback() {throw new IOException(); // 不會回滾
}
4、方法修飾符要求
public class ModelTrainingServiceImpl {// ? 正確:public方法@Transactionalpublic String createTask() {// 事務生效}// ? 錯誤:private方法事務不生效@Transactionalprivate void privateMethod() {// 事務不生效}// ? 錯誤:final方法無法被代理@Transactionalpublic final void finalMethod() {// 事務不生效}
}
5、Bean必須由Spring管理
// ? 正確:Spring管理的Bean
@Service
public class ModelTrainingServiceImpl {@Transactionalpublic void method() {// 事務生效}
}// ? 錯誤:手動new的對象
ModelTrainingServiceImpl service = new ModelTrainingServiceImpl();
service.method(); // 事務不生效
6、數據庫支持事務
-
使用支持事務的數據庫引擎(如MySQL的InnoDB)
-
正確配置數據源和連接
7、事務傳播行為
@Service
public class YourService {@Transactional(propagation = Propagation.REQUIRED)public void method1() {// 默認傳播行為}@Transactional(propagation = Propagation.REQUIRES_NEW)public void method2() {// 總是開啟新事務}
}