處理事務回滾


處理事務回滾

參考文獻:《極客時間-Java業務開發常見錯誤100例》https://time.geekbang.org/column/article/213295

大多數Spring Boot項目只需要在方法上標記@Transactional注解,即可一鍵開啟方法的事務性配置。

保證事務生效

  1. 務必確認調用 @Transactional 注解標記的方法是 public 的

    除非特殊配置(比如使用 AspectJ 靜態織入實現 AOP),否則只有定義在 public 方法上的 @Transactional 才能生效。原因是,Spring 默認通過動態代理的方式實現 AOP,對目標方法進行增強,private 方法無法代理到,Spring 自然也無法動態增強事務處理邏輯。
    
    如果要針對 private 方法啟用事務,動態代理方式的 AOP 不可行,需要使用靜態織入方式的 AOP,也就是在編譯期間織入事務增強代碼,可以配置 Spring 框架使用 AspectJ 來實現 AOP。你能否參閱 Spring 的文檔“Using @Transactional with AspectJ”試試呢?注意:AspectJ 配合 lombok 使用,還可能會踩一些坑。 https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-aspectj 
    
  2. 通過 Spring 注入的 Bean 進行調用的。使用 try…catch…來包裹標記了 @Transactional 注解的方法,必須通過代理過的類從外部調用目標方法才能生效。

    Spring 通過 AOP 技術對方法進行增強,要調用增強過的方法必然是調用代理后的對象。
    - CGLIB 通過繼承方式實現代理類,private 方法在子類不可見,自然也就無法進行事務增強;
    - this 指針代表對象自己,Spring 不可能注入 this,所以通過 this 訪問方法必然不是代理。
    
    正確使用:在 Service 內部注入自己調用自己的 方法() 可以正確實現事務,但更合理的實現方式是,讓 Controller 直接調用之前定義的 Service 的 方法() ,因為注入自己調用自己很奇怪,也不符合分層實現的規范
    

image

保證回滾

默認情況下,出現 RuntimeException(非受檢異常)或 Error 的時候,Spring 才會回滾事務。

修復方式:

  1. 自己捕捉,手動設置讓當前事務處於回滾狀態

    @Transactionalpublic void createUserRight1(String name) {
        try {
            userRepository.save(new UserEntity(name));
            throw new RuntimeException("error");
        } catch (Exception ex) {
            log.error("create user failed", ex); 
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
    
  2. 在注解中聲明rollbackFor ,期望遇到所有的 Exception 都回滾事務(來突破默認不回滾受檢異常的限制)

    @Transactional(rollbackFor = Exception.class)
    

子方法回滾,主方法不回滾

雖然捕獲了子方法的異常,但是因為沒有開啟新事務,而當前事務因為異常已經被標記為rollback了,所以最終還是會回滾。

解決方法:想辦法讓子邏輯在獨立事務中運行

  • 為注解加上 propagation = Propagation.REQUIRES_NEW 來設置 REQUIRES_NEW 方式的事務傳播策略,也就是執行到這個方法時需要開啟新的事務,並掛起當前事務。

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    

    主方法沒什么變化,同樣需要try catch捕獲異常,防止異常漏出去導致主事務回滾


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM