萬萬沒想到,這都能發(fā)現(xiàn) Bug?!
Bug 總會不約而至
大家好,我是魚皮,昨天工作中遇到一個挺好玩兒的小 Bug,和大家分享下,小白可懂~
事情是這樣的,為了保證發(fā)到線上的項目代碼能正常運行,每次構(gòu)建發(fā)布前,我們都會執(zhí)行一遍單元測試,對業(yè)務(wù)流程、一些增刪改查之類的代碼片段進(jìn)行驗證。
以前我上線項目都是有節(jié)奏有規(guī)劃的,也沒注意跑一遍單元測試要花多長時間,反正慢點我就先去干別的事兒。直到昨天,我急著修復(fù)一個線上 Bug,結(jié)果發(fā)現(xiàn)單元測試竟然特么跑了近 20 分鐘,直接給我整不會了。

雖說隨著項目功能的不斷增多,測試用例也越來越多,是會比以前多花一點時間。但整個測試數(shù)據(jù)庫量級都不過千,怎么會這么慢呢?
于是,我又執(zhí)行了一遍所有測試用例,觀察各用例的耗時,結(jié)果發(fā)現(xiàn)有一個簡單的查詢接口竟然執(zhí)行了近 10 分鐘。
由于不能透露真實的業(yè)務(wù)場景,給大家打個比方,這個接口的作用大概就是查詢某用戶信息以及他關(guān)聯(lián)的所有資產(chǎn)詳情列表,每個資產(chǎn)詳情都要查幾個不同的表才能得到完整數(shù)據(jù),相對比較耗時。
用一段偽代碼來描述,大概是這樣的:
//?耗時?0.1?秒
let?user?=?getUser();
//?循環(huán)
for(id?in?user.assetIds)?{
??//?耗時?0.1?秒
??let?asset?=?getDetail();
??//?耗時?0.1?秒
??asset.xx?=?getXX();
??//?耗時?0.1?秒
??asset.yy?=?getYY();
??//?耗時?0.1?秒
??asset.zz?=?getZZ();
}
可以看出,如果該用戶有很多資產(chǎn)的話,查詢耗時將線性增加。
那肯定有同學(xué)要吐槽了:為啥是查詢所有,而不是分頁一批一批去查呢?這個就得從實際的業(yè)務(wù)場景去考慮了。我們系統(tǒng)情況是:用戶一般不會有太多資產(chǎn)詳情的,而且要把數(shù)據(jù)全部返回給前端展示,所以不分頁會更方便些。
但萬萬沒想到啊,每次測試插入資產(chǎn)的方法時,我都指定了該資產(chǎn)的所屬用戶 id = 1!日積月累,最終導(dǎo)致該用戶名下的資產(chǎn)數(shù)多達(dá)近千個!然后又恰好,我測試該查詢接口時,查的就是用戶 id = 1 的數(shù)據(jù),就導(dǎo)致了悲劇的發(fā)生。

解決方案也很簡單,把順序查詢轉(zhuǎn)為并發(fā)查詢即可。
具體的步驟就是開一個線程池,然后 Java 的話可以用 CompletableFuture 類來創(chuàng)建并發(fā)查詢?nèi)蝿?wù),每個任務(wù)負(fù)責(zé)查詢一個資產(chǎn)的詳情,最后等所有資產(chǎn)詳情都查詢好,再整體返回。
Java 代碼大概是這樣的(不保證能運行):
//?開個線程池,取任務(wù)執(zhí)行
ExecutorService?executor?=?new?ThreadPoolExecutor(
??8,?100,?5,
??TimeUnit.MINUTES,
??new?ArrayBlockingQueue<>(10000)
);
//?任務(wù)列表
List>?fList?=?new?ArrayList<>();
for?(int?id?:?assetIds)?{
??//?創(chuàng)建任務(wù)
??CompletableFuture?f?=?CompletableFuture.supplyAsync(
????()?->?{
??????Asset?asset?=?getDetail();
??????asset.xx?=?getXX();
??????asset.yy?=?getYY();
??????asset.zz?=?getZZ();
?????return?asset;
???},
????executor
??);
??fList.add(f);
}
//?阻塞,等待所有任務(wù)執(zhí)行完成
List?CompletableFuture
??.allOf(fList.toArray(new?CompletableFuture[0]))
??.get();
唉,本來是想著就幾條數(shù)據(jù)沒必要用并發(fā)查詢的,沒想到還是潛移默化間影響了自己開發(fā)上線項目的效率。
不過,這次的小事件也再次說明了單元測試的重要性,這玩意不僅能測出程序不能正常運行的問題,還能側(cè)面反映出你系統(tǒng)上存在的風(fēng)險和缺陷。所以,大家做項目時還是不能偷懶,要好好寫單元測試哈!
以上就是本期分享,有幫助的話還請給魚皮一個 點贊 + 在看 ,謝謝大家!

往期推薦
