在使用Spring的@Transactional
註解時,有時會出現事務失效的情況。這通常是由於一些常見的配置或使用錯誤引起的。以下是事務失效的原因和處理方法:
常見原因
-
方法可見性
@Transactional
註解的方法必須是public
的。Spring AOP代理只會攔截public
方法,非public
方法(如private
、protected
或預設可見性的方法)將不會被代理,因此事務將不會生效。@Transactional public void myTransactionalMethod() { // Method logic }
-
方法內部呼叫 如果在同一個類內部呼叫一個被
@Transactional
註解的方法,該註解將失效。這是因為Spring AOP基於代理機制,內部方法呼叫不會經過代理物件。public void nonTransactionalMethod() { myTransactionalMethod(); // This will not be transactional }
解決方法:將事務方法移到另一個
@Service
類中,透過依賴注入呼叫。@Service public class MyService { @Autowired private AnotherService anotherService; public void nonTransactionalMethod() { anotherService.myTransactionalMethod(); } } @Service public class AnotherService { @Transactional public void myTransactionalMethod() { // Method logic } }
-
代理機制 預設情況下,Spring AOP使用JDK動態代理或CGLIB代理。確保在Spring配置中啟用了AOP支援:
@Configuration @EnableTransactionManagement public class AppConfig { // Configuration beans }
-
事務傳播行為 不正確的事務傳播行為設定可能導致事務失效。例如,
@Transactional(propagation = Propagation.NOT_SUPPORTED)
將導致事務在當前方法中被掛起。@Transactional(propagation = Propagation.REQUIRES_NEW) public void myTransactionalMethod() { // Method logic }
-
異常處理 事務只會在方法丟擲未捕獲的執行時異常(
RuntimeException
)時回滾。受檢異常(CheckedException
)預設不會導致事務回滾。@Transactional public void myTransactionalMethod() throws Exception { try { // Method logic } catch (SpecificException e) { throw new RuntimeException(e); // Ensure rollback } }
-
Spring Boot 和 JPA 配置 如果使用Spring Boot和JPA,確保正確配置了事務管理器。
@SpringBootApplication @EnableTransactionManagement public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
處理方法
- 檢查方法可見性:確保被
@Transactional
註解的方法是public
的。 - 避免內部方法呼叫:將事務方法移到另一個服務類中,透過依賴注入呼叫。
- 啟用AOP支援:在Spring配置中啟用事務管理和AOP支援。
- 正確設定傳播行為:根據需求設定正確的事務傳播行為。
- 正確處理異常:確保丟擲未捕獲的執行時異常以觸發回滾。
- 檢查配置:確保Spring Boot和JPA的配置正確。
示例程式碼
// Configuration class @Configuration @EnableTransactionManagement public class DataSourceConfig { // DataSource and TransactionManager beans } // Service class @Service public class MyService { @Autowired private AnotherService anotherService; public void nonTransactionalMethod() { anotherService.myTransactionalMethod(); } } @Service public class AnotherService { @Transactional public void myTransactionalMethod() { // Method logic } }
透過確保以上因素正確配置和使用,可以避免@Transactional
失效的問題,確保事務管理生效。