Spring service本類中方法互相調用事物失效問題


簡介

Spring事物利用的是AOP,動態代理采用CGLIB代理(默認,也可以用Proxy代理,但是Proxy代理效率低於CGLIB代理)。故只要弄懂Spring的AOP實現,就知道為什么service本類中方法互相調用會導致事物失效。

失效案例

service層代碼

 public void  moneyTestOne(){
        //1.查詢病人基本信息
        List<TBICXX> tbicxx = basisDao.getTBICXX();
        //2.根據CMZH更新TBMZFYHZ
        Integer TBMZFYHZCount = tbmzfyhzDao.updateByCMZH("王五", "1903003643");
        log.info("更新TBMZFYHZ影響行數{}",TBMZFYHZCount);
        this.moneyTestTwo();

    }

    @Transactional(rollbackFor = Exception.class,propagation=Propagation.REQUIRED)
    public void  moneyTestTwo(){
        //3.根據CMZH更新TBMZFYMXGH
        Integer integer = tbmzfymxghDao.updateByCMZH("王五", "2107000224");
        log.info("更新TBMZFYMXGH影響行數{}",integer);
        int i=2/0;
    }

Test層代碼

/**
     * 測試其AOP事物(CGLIB代理):
     *   如moneyTestOne不添加事物,則moneyTestTwo事物及其一切傳播行為將失效,這是由於spring的AOP的Cglib代理造成
     *   同理: moneyTestOne添加事物,moneyTestTwo事物及其一切傳播行為也將失效,moneyTestTwo運行在moneyTestOne事物中。
     *   $$EnhancerBySpringCGLIB$$2364c0b7 代理
     **/
    @Test
    public void testTransationalPropagation(){
        log.info("測試開始,代理類{}",springTransactionSqlserverServiceImpl.getClass());
        springTransactionSqlserverServiceImpl.moneyTestOne();
    }

運行前
image
運行后
image
結論
moneyTestTwo方法事物並不生效,要想事物生效,只需要在moneyTestOne方法上加上事物注解(此方法同理會導致moneyTestTwo方法傳播行為失效),

失效分析

Spring通過AopProxy接口,抽象了這兩種實現,實現了一致的AOP方式:
image
現在看來,這種抽象同樣帶了一個缺陷,那就是抹殺了Cglib能夠直接創建普通類的增強子類的能力。下圖顯示了Spring的AOP代理類的實際調用過程:
image

解決辦法

事物聲明避免在一個類中互相調用,即moneyTestOne和moneyTestTwo要么都使用事物,要么直接分成兩個類。

Gitee代碼地址

https://gitee.com/zhuayng/foundation-study/tree/develop/SpringBootDemo/src/main/java/com/yxkj/springbootdemo/service/impl


免責聲明!

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



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