javascript
Spring中解决事务以及异步注解失效
Spring中解決事務以及異步注解失效
一、重現@Transaction失效的場景
? ? ? ? 有如下業務場景,新增訂單后,自動發送短信,下面的代碼在同一個類中:
@Transaction
public void addOrder(OrderInfo? orderInfo){?
? ? ? ? orderMapper.insert(orderInfo);
? ? ? ? try{
? ? ? ? ? ? ? ? sendMesg(orderInfo?);
? ? ? ? }cach(Exception e){
? ? ? ? ? ? ? ? e.printStrace();
????????}
}
@Transaction
public void sendMesg(?OrderInfo? orderInfo?){
? ? ? ? mesgMapper.insert(orderInfo?);
? ? ? ? throws new RuntimeException("發送短信出現異常!");
}
? ? ? ? 上面的偽代碼模擬新增訂單后,自動發送短信的業務場景。兩個操作被標識為事務,為了不影響發送短信出現異常影響訂單的插入,在調用發送短信的方法時,通過 try....cach...捕獲其異常并處理,不影響訂單表的插入。
? ? ? ? 因為sendMesg標識為事務,其拋出異常后,事務按正常邏輯來說,事務會進行回滾,即短信表中不會插入記錄。然而事與愿違,出現的結果是短信表也插入了記錄。
二、重現異步注解失效的場景
1、異步注解@Async介紹
? ? ? ? 基于@Async標注的方法,稱之為異步方法,這些方法在執行的時候,spring將會為其開辟獨立的線程執行,調用者無需等待它的完成,即可繼續其他的操作。
2、如何使用@Async
? ? ? ? 增加 aspectj 相關的依賴;
? ? ? ? 修改 spring配置文件,在配置文件中增加如下配置:
? ? ? ? <task:annotation-driven executor = "annotationExecutor"? />
? ? ? ? <task:executor id="annotationExecutor" pool-size="20" />
? ? ? ? 在方法上加上@Async注解。
3、業務場景介紹
預定旅游套餐業務場景
@Transaction?
public void planTourismPackages(Order orderInfo){
? ? ? ? dealPassengerTicketBusiness(orderInfo);
? ? ? ? dealHotelBusiness(orderInfo);
? ? ? ? sendMesg(orderInfo);
? ? ? ? sendEmial(orderInfo);
?}
@Async
public void sendMesg(?OrderInfo? orderInfo?){
? ??????mesgMapper.insert(?orderInfo??);? ? ? ? ?
? ??????throws new RuntimeException("發送短信出現異常!");?
}
? ? ? ? 預定旅游套餐時,首先處理機票預定業務,然后處理酒店預定業務,最后發送短信和郵件。發送短信和郵件屬于輔助業務,可以讓其異步執行,所以在方法上加了@Async注解,讓其異步執行。為了演示效果,我將planTourismPackages方法標識為事務處理,故意讓sendMesg方法拋出異常。按我們預想,因為sendMesg方法異步執行,其拋出異常應該不會影響planTourismPackages事務的提交,機票預定表和酒店預定表應該會插入記錄。但是,事與愿違,sendMesg拋出異常導致planTourismPackages事務會滾了,說明@Async并未生效。
三、原因分析
? ? ? ? 為什么會出現上面的事務和異步注解失效呢?
? ? ? ? spring聲明式事務和異步注解的實現都是基于spring aop,即對標識的方法進行增強。spring aop的底層實現原理是 jdk 動態代理。因為事務注解方法,異步方法的調用的方法在同一個類中,所以發送短信方法是在調用方法的代理對象中執行的,沒有對發送短信方法進行增強。如下圖:
orderMapper.insert(?orderInfo?);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
try{?
? ? ? ? ?this.sendMesg(?orderInfo??);?
?}cach(Exception e){?
? ??????e.printStrace(); ??
?}?
public void planTourismPackages(Order orderInfo){? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
????????dealHotelBusiness(?orderInfo?);?
????????dealPassengerTicketBusiness(?orderInfo?);??
????????this.sendMesg(?orderInfo?);
????????this.sendEmial(?orderInfo?);??
}
四、解決方案
? ? ? ? 要解決上面的問題,必須要實現發送短信方法的增強,使其能夠成為事務或者異步方法,即讓代理生效。spring的解決方案如下:
? ? ? ? 1、在spring配置文件xml新增如下語句:
? ? ? ? 先開啟cglib代理,開啟 exposeProxy=true,暴露代理對象
? ? ? ? <aop:aspectj-autoproxy expose-proxy="true"/>
? ? ? ? 2、使用AopContext 獲取當前對象的動態代理。
? ? ? ? 修改配置文件后,代碼修改,用獲取到的動態代理去執行發送短信方法,如下:
? ? ? ? TourServer currentProxy = (TourServer?)AopContext.currentProxy();
? ??????currentProxy.sendMesg(orderInfo);
? ??????currentProxy.sendEmail(orderInfo);
總結
以上是生活随笔為你收集整理的Spring中解决事务以及异步注解失效的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享一个用Axure写的PRD文档
- 下一篇: SpringCloud 入门教程(六):