專案開發中記憶體分頁的使用場景(Java)
記憶體分頁在專案中一般是不推薦使用的,因為效率很低。掃描資料庫相關表的所有資料,並全部載入進記憶體,然後返回需要的資料(可能載入了幾萬條到記憶體最終返回5條),極大的消耗了記憶體。
但在目前負責開發的狐小E智慧辦公(https://www.hixiaoe.com)平臺中,由於某些特殊場景,所以必須通過記憶體分頁的方式解決。
場景1 (批量in查詢)
在excel批量匯入員工資料時,需要以手機號作為唯一條件校驗資料是否已存在,若存在,則以excel中的內容,作為最新記錄進行更新,若不存在,則直接更新。
這樣的操作就會導致每匯入一條就必須查一下資料庫看資料是否存在,這樣效率很低,優化的方法就是,將要匯入的員工手機號全部取出後,用手機號作為條件,去資料庫中以in
這時就會有個問題:假如匯入的資料有5000條,就表示sql拼接的in條件就有5000個引數,Oracle資料庫中IN引數個數不能超過1000,否則會報異常。而Mysql中雖然對in無限制,但是sql預設長度是1M (my.ini 中的max_allowed_packet可調節大小)雖然可以通過引數調節,但是站在程式層面上可能調節成2M也不夠,當調的引數過大,Mysql還會自動設定回預設值,站在程式設計師的角度上,還是從程式碼角度解決問題比較穩妥。
這時候就可以使用記憶體分頁了,將記憶體中的資料根據實際情況分批次訪問,比起一次次的迴圈查資料庫,效率肯定高,又不至於出現一次in查詢導致sql過長而報錯。
場景2(模糊查詢加密資料)
在業務實現的過程中,有這麼一張表:待離職員工臨時表,這個表所涉及的業務就是執行員工離職操作前,若存在待處理事務未提交,則員工資訊會被放到這個表中,等待離職事務處理完畢後,即可作真正的離職操作,然後刪除這個表對應的資料。表裡的資料由於保密性,部分欄位(姓名,手機號等) 都做了加密處理。
分析這個表的特點:
①資料量比較小(只有類似管理員之類的角色,有未交接完成的事務,才會儲存在這張表裡)
②頁面按條件模糊查詢的資料在資料庫裡都是加密儲存的
這種場景下就可以使用記憶體分頁查詢到記憶體中,解密後再和前端傳遞的搜素詞做模糊匹配。資料庫其實支援加解密,但目前資料的加密未使用資料庫的方式而且,實際使用場景上該表資料量極少,所以一次查詢到記憶體裡比資料庫執行解密的效率更快。綜合考慮用記憶體分頁的方式更合理。
實現方式
利用java8中 Steam的.skip() 和 limit() 實現
/**
* 記憶體分頁
*
* @param data 資料
* @param pageNum 當前頁
* @param pageSize 分頁條數
* @return
*/
public List<Object> pageOprateInMemory (List<Object> data, Integer pageNum, Integer pageSize) {
if (CollectionUtils.isEmpty(data)) {
return null;
}
// 根據當前頁和分頁條數 從總記錄數中取資料
List<Object> temps = data.stream().skip(pageSize * (pageNum - 1)).limit(pageSize)
.collect(Collectors.toList());
return temps;
}
通過以上記憶體分頁的操作,提升了專案資料查詢的效率,減少了資料庫對sql限制的錯誤,對於前端模糊查詢少量加密資料也有較好的呈現效果。
作者介紹:小文文,狐小E智慧辦公(https://www.hixiaoe.com)開發工程師,專注移動辦公軟體的SaaS平臺建設以及輕應用開發