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