在Service中拋出異常事務未回滾問題分析與解決


1.問題提出:
在service中寫方法時,拋出了一個Exception, 本來目的是為了讓事務回滾, 但事實上沒有回滾,產生了臟數據。
代碼如下:
@Override
@Transactional
public void insertInSingle(String type, MobileEditInDTO dto) throws Exception {
        MaterialOtherInSingle otherInSingle = otherInService.findEntityByProperty("tableNo", tableNo);                
        //其他入庫單表頭
        otherInSingle.setServiceTypeID(serviceTypeService.getServiceType(dto.getServiceTypeId()));
        otherInSingle.setInCome(storageTypeService.getStorageType(dto.getStorageTypeId()));
        otherInSingle.setInStorageDate(dto.getInDate());
        throw new Exception(111);
}
在這個方法中用hql獲得了一個持久態對象,並設置了新的屬性,在最后演示的時候拋出了異常,但是最后並未回滾。

2.問題分析
在這個方法中加入了@Transactional注解,聲明了這是一個事務,其原理就是AOP。平時我們都是這么做的,但是並不是很清楚原理是什么。

注解其實只是一個聲明,真正的目的在聲明之后這個方法成為了一個連接點,說到連接點又不得不說AOP,
AOP說簡單點其實就是一個動態代理,我們service之所以要先聲明接口再有一個實現類其實很大程度上為了實現動態代理,實現動態代理之后我們可以省去很多在方法層面上重復的代碼。
不理解的請自行百度關鍵詞: AOP, 動態代理,這個東西很復雜一下子也說不清楚(其實我也不是很懂)。

說回來這個@Transactional,它的切入點(PointCut)其實就是拋異常,在拋出異常的時候調用增強處理(Advice)中的方法將事務回滾掉,但是這個拋異常拋的不是普通的自Exception中繼承過來的異常,
unchecked exception回滾。也就是默認對RuntimeException()異常或是其子類進行事務回滾。雖然RuntimeException繼承自Exception,但是切入點要更具體一些。

當然如果要讓所有Exception都回滾,在@Transactional(rollbackFor = Exception.class) 上加個參數就好了。
但是要注意的事,如果聲明了@Transactional,但是又在方法里面自己捕獲了異常,也就是try catch掉了,那就不會回滾了,因為切入點根本沒捕獲到,也談不上調用增強處理中的方法了。

3.問題解決
上面啰嗦了這么多,解決這個問題無非就是兩個辦法:
1.拋出RuntimeException
2.拋出Exception,同時在事務聲明中加上@Transactional(rollbackFor = Exception.class)

如果有寫到不對的地方,歡迎多多指正 
還要再說明一點,在controller中調用service的這個已經解決的方法是可以try catch的,不用擔心不會回滾,因為已經被aop監聽到了。


免責聲明!

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



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