新聞中心
作為后端開發(fā)的程序員,我們常常會的一些相對比較復(fù)雜的邏輯,比如我們需要給前端寫一個調(diào)用的接口,這個接口需要進行相對比較復(fù)雜的業(yè)務(wù)邏輯操作,比如會進行,查詢、遠程接口或本地接口調(diào)用、更新、插入、計算等一些邏輯,將最終接口的返回結(jié)果給到前端,而經(jīng)過這么一系列的業(yè)務(wù)邏輯操作,接口對DB的操作、對代碼業(yè)務(wù)邏輯判斷、進行接口調(diào)用這些都是需要時間的,而只要這是一個事務(wù)操作,每次對數(shù)據(jù)庫進行的交互都會產(chǎn)生一條事務(wù)記錄。

那么這樣就會對我們接口返回的效率產(chǎn)生影響,而且這個影響是隨著數(shù)據(jù)量的增長而增長的,這時候我們就需要對一整個大事務(wù)進行拆分,從而提升整體接口的效率。
何為大事務(wù)
就拿我最近開發(fā)寫的一個接口來說吧,大致是這么一個邏輯,我需要根據(jù)頁面的提交的數(shù)據(jù)生成一個收款單,整體接口處理的業(yè)務(wù)如下,我把它們寫在了一個接口里,可以理解為這是一個大事物,這個接口執(zhí)行的時間是相對比較長的,而且將這些邏輯全部寫在一個接口里面,本身來說也是不太合理的。
圖片
大事務(wù)存在的一些問題
并發(fā)數(shù)據(jù)不一致
不加鎖的情況下,由于種種原因第一次接口的調(diào)用還沒執(zhí)行完,還在等待第三方的調(diào)用回寫數(shù)據(jù),第二次調(diào)用又進來對數(shù)據(jù)進行了更改,第二次調(diào)用先執(zhí)行完,這時候第一次接口調(diào)用拿到了第三方接口的返回,去回寫狀態(tài)發(fā)現(xiàn)已經(jīng)被更新,導(dǎo)致無效操作。
加鎖容易阻塞
加鎖的情況下, 不會出現(xiàn)數(shù)據(jù)不一致情況,但是由于大事物執(zhí)行時間較長,容易造成鎖超時失效,鎖定太多的數(shù)據(jù)造成阻塞,嚴重影響效率。
Undo logo事務(wù)日志性能問題
容易造成Undo logo日志數(shù)據(jù)量很大,降低了日志的查詢性能,包括對事務(wù)的回滾效率也會降低。
并發(fā)數(shù)據(jù)庫壓力太大
并發(fā)量達到一定程度,會對數(shù)據(jù)庫讀寫造成不小的壓力,會堆積大量等待線程。
如何優(yōu)化大事務(wù)
事務(wù)里面不要進行遠程RPC調(diào)用
首先事務(wù)里面進行遠程的接口調(diào)用,如果不采用分布式事務(wù)框架,本身就會存在事務(wù)不一致的情況,無法進行數(shù)據(jù)的回滾操作,并發(fā)情況下遠程服務(wù)響應(yīng)不及時,會出現(xiàn)接口返回不一致問題,當(dāng)然必須采用異步調(diào)用,后面會提到。
編程型事務(wù)更加靈活
聲明式事務(wù)只需要加在方法頭加@Transactional注解即可開啟事務(wù),但是還是不太靈活,意味著整個方法所進行對數(shù)據(jù)庫操作都要加進事務(wù),當(dāng)然一次查詢也要進入事務(wù),這并不是我們想要的,我們在update、insert操作上進行事務(wù)操作,方便進行回滾。
public Boolean transactionCommit(String userName) {
//查詢用戶
SysUser sysUser = userMapper.selectUserByUserName(userName,null);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
if (null != sysUser) {
//用戶信息狀態(tài)更新 status更新為1
userMapper.updateStatus(userName);
}
} catch (Exception e){
//回滾
transactionStatus.setRollbackOnly();
}
}
});
//再次查詢
SysUser sysUser1 = userMapper.selectUserByUserName(userName,"1");
/log/.info("狀態(tài)為1的用戶信息"+JSON./toJSONString/(sysUser1));
return true;
}編程式事務(wù)的靈活點在于可以控制事務(wù)執(zhí)行方法,運用transactionTemplate類進行事務(wù)操作,查詢操作可以寫在外面,這樣查詢獲取數(shù)據(jù)的操作就不會進入mysql事務(wù)表。
數(shù)據(jù)分批處理
對于事務(wù)的更新或者插入,前端可能會有批量操作,大規(guī)模數(shù)據(jù)的批量更新、插入也會對事務(wù)接口產(chǎn)生影響,一旦其中有更新或插入失敗,為了保證事務(wù)的一致性,整個操作都要進行回滾;
- 前端:可以限制數(shù)據(jù),對后端接口的訪問,可以將數(shù)據(jù)進行分頁,多次請求,可以避免事務(wù)提交大量數(shù)據(jù)。
- 后端:也可以去數(shù)據(jù)進行分頁處理,例如每次可以限制50條進行操作,如果是新增邏輯,使用Mybatis的批量更新大大提升效率
List> partition = Lists.partition(receivableFeeSaveDTOList, 50);
大事務(wù)拆分小事務(wù)
可以將一個事務(wù)接口,拆分成多個事務(wù)接口,并且每個事務(wù)接口只做一件事,比如上面的收款單生成接口,金額回寫、第三方接口調(diào)用、調(diào)用后的結(jié)果回寫都可以抽成一個哥小事務(wù)接口。
就好比做一件很復(fù)雜的事情,咋一眼看上去很復(fù)雜,但是我們把這復(fù)雜的步驟,進行多個步驟的拆分,每個階段完成每個階段的事情,就可以將整個過程簡化,看起來就沒那么復(fù)雜了。
異步并行處理
重中之重,事務(wù)里如果無法避免遠程調(diào)用,那么肯定是需要進行異步調(diào)用,因為無法保證遠程接口的及時響應(yīng)性,CompletableFuture異步編排特性可以用到,task1和task2任務(wù)結(jié)束后,執(zhí)行task3。
CompletableFuture總結(jié)
可見大事務(wù)是我們接口效率低下的罪魁禍首,有時候我們?yōu)榱丝焖賹崿F(xiàn)功能,可能會忽略一些關(guān)乎于性能的東西,而這些東西是我們能力提升的一個契機。
本文標題:接口中的大事務(wù),該如何進行優(yōu)化?
URL網(wǎng)址:http://www.dlmjj.cn/article/djoojhc.html


咨詢
建站咨詢
