在Controller中添加事務管理


文章參考了此博客: https://blog.csdn.net/qq_40594137/article/details/82772545

 

寫這篇文章之前先說明一下:

       1. Controller中添加事務管理,是可行的,但是強烈不推薦,因為不符合實際開發場景,還會導致一系列問題

       2. 事務請在Service處理,所有的業務邏輯請寫在 Service, Service中異常請拋出,慎用 try...catch捕獲異常

 

寫這邊文章的背景:

       公司有個老的項目,springMVC + spring + mybatis,事務是在Service層處理的,但是之前的開發人員把很多業務邏輯寫在了 Controller,出現了操作失敗仍然將數據寫入數據庫的bug.....,於是開始研究在 Controller中添加事務管理

 

Controller中添加事務管理步驟:

    1. spring.xml中事務配置不變

    2. 在spring-mvc.xml中定義事務配置:

         A: 命名空間中 加入約束 不加項目啟動會報異常:
             xmlns:tx="http://www.springframework.org/schema/tx"
             http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

         B:  定義事務注解解析  <tx:annotation-driven transaction-manager="transactionManager" /> 

   3. 在需要控制事務的Controller 類或者方法上使用 @Transactional(rollbackFor = {Exception.class}) ,當出現異常回滾

       需要注意的是:  Controller層只支持 @Transactional 注解式事務!

                           

關於為什么要在spring-mvc.xml中添加 <tx:annotation-driven transaction-manager="transactionManager" />  的說明:

     錯誤的方式----通過修改spring.xml中的配置來實現在controller中控制事務會發現事務無效,如下:

<aop:config>  
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* net.*.controller.*.*(..))"/></aop:config> 

      原因如下:  spring容器和spring-mvc是父子容器。在服務器啟動時,會先加載web.xml配置文件 ==> 再加載spring配置文件 ==> 再回到web.xml【加載監聽器;加載過濾器;加載前端控制器】==>再加載springMVC配置文件,在Spring配置文件中,我們掃描注冊的是service實現類,就算掃描注冊了controller 也會在后面加載SpringMVC配置文件[掃描注冊controller]覆蓋掉,所以想要在controller中實現事務管理,僅在spring配置文件配置<tx:annotation-driven>或<aop:config>是沒有效果的,必須將事務配置定義在Spring MVC的應用上下文(spring-mvc.xml)中。在spring-framework-reference.pdf文檔中說明了: <tx:annoation-driven/>只會查找和它在相同的應用上下文件中定義的bean上面的@Transactional注解

 

關於 @Transactional 注解的一些說明:

     有篇博客寫的很好,我就直接鏈接了  https://www.jianshu.com/p/befc2d73e487

 

關於@Transaction 事務不起作用的總結:

       @Transaction不起作用的情況:1.靜態(static )方法 

                                                         2.(private)私有化方法  

                                                         3.當本類的使用@Transactional的方法被本類的其它沒有開啟事務的方法調用時,不會開啟事務。

                                                             使用@Transactional的方法被其它類調用時,按照正常的事務傳播行為規則開啟事務

                                                         4.未開啟注解解析: 配置文件必須加<tx:annotation-driven />,否則不解析@Transactional

                                                         5.異常被try{}catch(){}捕捉到了,有異常就不會回滾。

                                                         6. 數據庫引擎要支持事務: 如果是mysql,注意表要使用支持事務的引擎,比如innodb,如果是myisam,事務是不起作用的

 

項目中問題的最終處理:

              由於 Controller 層中異常不能直接拋到用戶,對異常進行了try{}catch(){},導致事務回滾失效,無法通過在 Controller 層添加事務管理來實現事務功能,

       所以只能有用以下方式來處理:

       1. 將業務邏輯代碼移到 service 來處理 : 推薦方法

       2. 如果業務邏輯復雜,在維護的時候無法保證邏輯正確的情況下,只有手動編寫事務代碼來實現回滾了,具體代碼如下:(不推薦)

         

//在每個controller中注入transactionManager
@Resource
private PlatformTransactionManager transactionManager;
 
@PostMapping(value = "setCode")
@ResponseBody
public void setCode(Invoice invoice, InvoiceAddress invoiceAddress,String token,String orderIDs,
                    Integer pid,HttpServletResponse response){
 
    DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
    defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
 
    try {
        invoiceService.insert(token,pid,invoice);
        int iID= invoice.getId();
        String substring = orderIDs.substring(0, orderIDs.length()-1);
        String[] split = substring.split(",");
        for (String string2 : split) {
            bOrderService.updateIStatus("1",string2);
        }
        invoiceOrderService.insert(iID,substring);
        if(Integer.parseInt(invoice.getiType())==1){
            invoiceAddressService.insert(iID,invoiceAddress);
        }
 
        System.out.println("======制造一個運行時異常aa======");
        System.out.println("運行時異常:"+100/0);
 
        //沒有異常便手動提交事務
        transactionManager.commit(status);
        printJson(response,result(200,"ok"));
    }catch (Exception e){
        //有異常便回滾事務
        transactionManager.rollback(status);
        e.printStackTrace();
        printJson(response,result(500,"false"));
    }
 
}

 

  

 

 

  

 

 

      

 

      


免責聲明!

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



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