關於事務回滾註解@Transactional

阿迪di發表於2024-07-09

在使用Spring的@Transactional註解時,有時會出現事務失效的情況。這通常是由於一些常見的配置或使用錯誤引起的。以下是事務失效的原因和處理方法:

常見原因

  1. 方法可見性 @Transactional註解的方法必須是public的。Spring AOP代理只會攔截public方法,非public方法(如privateprotected或預設可見性的方法)將不會被代理,因此事務將不會生效。

    @Transactional
    public void myTransactionalMethod() {
        // Method logic
    }

  2. 方法內部呼叫 如果在同一個類內部呼叫一個被@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
        }
    }
  3. 代理機制 預設情況下,Spring AOP使用JDK動態代理或CGLIB代理。確保在Spring配置中啟用了AOP支援:

    @Configuration
    @EnableTransactionManagement
    public class AppConfig {
        // Configuration beans
    }
  4. 事務傳播行為 不正確的事務傳播行為設定可能導致事務失效。例如,@Transactional(propagation = Propagation.NOT_SUPPORTED)將導致事務在當前方法中被掛起。

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void myTransactionalMethod() {
        // Method logic
    }
  5. 異常處理 事務只會在方法丟擲未捕獲的執行時異常(RuntimeException)時回滾。受檢異常(CheckedException)預設不會導致事務回滾。

    @Transactional
    public void myTransactionalMethod() throws Exception {
        try {
            // Method logic
        } catch (SpecificException e) {
            throw new RuntimeException(e); // Ensure rollback
        }
    }
  6. Spring Boot 和 JPA 配置 如果使用Spring Boot和JPA,確保正確配置了事務管理器。

    @SpringBootApplication
    @EnableTransactionManagement
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }

處理方法

  1. 檢查方法可見性:確保被@Transactional註解的方法是public的。
  2. 避免內部方法呼叫:將事務方法移到另一個服務類中,透過依賴注入呼叫。
  3. 啟用AOP支援:在Spring配置中啟用事務管理和AOP支援。
  4. 正確設定傳播行為:根據需求設定正確的事務傳播行為。
  5. 正確處理異常:確保丟擲未捕獲的執行時異常以觸發回滾。
  6. 檢查配置:確保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失效的問題,確保事務管理生效。

相關文章