@Transactional事務出現異常不回滾的處理
一、背景:
目前很多專案的事務處理都是利用Spring的註解式事務實現的(@Transactional)。
在測試事務回滾的過程中發現如下現象:
throw new RuntimeException("xxxxxxxxxxxx"); 事務回滾
throw new Exception("xxxxxxxxxxxx"); 事務沒有回滾
二、關於spring事務使用說明:
基於Spring AOP的事務管理,即宣告式事務管理,預設是針對RuntimeException回滾,既預設只對RuntimeException()及其子類進行事務回滾;非執行時型別的異常預設是不會回滾的。
spring aop 異常捕獲原理:被攔截的方法需顯式丟擲異常,並不能經任何處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾,預設情況下aop只捕獲 RuntimeException 的異常,但可以通過配置來捕獲特定的異常並回滾
換句話說在service的方法中不使用try catch 或者在catch中最後加上throw new runtimeexcetpion(),這樣程式異常時才能被aop捕獲進而回滾
三、依賴事務管理的業務程式碼中出現異常該如何處理?
spring xml配置處理
1、針對該業務程式碼進行封裝,二次丟擲RuntimeException型別的異常;
2、利用硬編碼的方式,藉助spring api對事務進行顯式的回滾;
3、在spring配置檔案中對rollback-for屬性賦值。Tip:該配置也可以直接加在註解上。
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" rollback-for="com.wangcw.exception.XyzException"/> </tx:attributes> </tx:advice>
同時,Spring配置檔案中也可以宣告出不進行回滾的異常。
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="update*" no-rollback-for="IOException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
springboot處理方式
方案1.例如service層處理事務,那麼service中的方法中不做異常捕獲,或者在catch語句中最後增加throw new RuntimeException()語句,以便讓aop捕獲異常再去回滾,並且在service上層(webservice客戶端,view層action)要繼續捕獲這個異常並處理
方案2.在service層方法的catch語句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();語句,手動回滾,這樣上層就無需去處理異常
@GetMapping("delete")
@ResponseBody
@Transactional
public Object delete(@RequestParam("id") int id){
if (id < 1){
return new MessageBean(101,"parameter wrong: id = " + id) ;
}
try {
//delete country
this.countryRepository.delete(id);
//delete city
this.cityRepository.deleteByCountryId(id);
return new MessageBean(200,"delete success");
}catch (Exception e){
logger.error("delete false:" + e.getMessage());
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return new MessageBean(101,"delete false");
}
}