Mybatis集成MySQL使用游標查詢處理大批量數(shù)據(jù)方式
背景
基于數(shù)據(jù)的時間范圍查詢,給符合條件的用戶推送積分即將到期的提醒。
初期用戶量小使用最普通簡單的分頁查詢掃描數(shù)據(jù)處理數(shù)據(jù)沒問題。隨著用戶量的上升表數(shù)據(jù)已經(jīng)上千萬,每天掃描處理的數(shù)量也超百萬,limit分頁出現(xiàn)了慢sql,任務執(zhí)行時間也達不到預期了。
上述方案出現(xiàn)瓶頸后考慮放棄limit方案,使用游標的方式進行全量數(shù)據(jù)的獲取,這樣一來SQL執(zhí)行快任務執(zhí)行也快。
MySQL游標查詢
useCursorFetch
使用游標查詢時,必須在jdbc url上設置連接屬性參數(shù)useCursorFetch=true
FetchSize
在設置了useCursorFetch=true后,需要在SQL中指定fetchSize,即一次獲取的數(shù)據(jù)量。
如果不設置fetchSize參數(shù),則執(zhí)行時仍然是全量返回,可能會出現(xiàn)OOM。
Mybatis集成Cursor查詢
mapper接口方法返回值聲明為Cursor類型,下面是SQL和Mapper的示例。
Cursor<Long> selectExpireCouponMember(@Param("endTime") String endTime); <select id="selectExpireCouponMember" resultType="java.lang.Long" fetchSize="5000"> select distinct member_id from t_dj_coupon where end_time > end_time < #{endStartTime} and end_time < #{endTime} </select>
下面是基于上面的SQL做大量數(shù)據(jù)查詢后寫入文件的代碼示例。
String fileName = DateFormatUtils.format(System.currentTimeMillis(), DateUtils.PATTERN_YYYY_MM_DD) + "_status_push_member.txt"; File file = new File(fileName); file.createNewFile(); fileWriter = new FileWriter(file); bufferedWriter = new BufferedWriter(fileWriter); try (SqlSession sqlSession = sqlSessionFactory.openSession()) { DjCouponMapper mapper = sqlSession.getMapper(DjCouponMapper.class); try (Cursor<Long> cursor = mapper.selectStartCouponMember(startDate, startDateEnd, BrandContextHolder.getBrandMdCode())) { Iterator<Long> iterator = cursor.iterator(); Set<Long> couponMemberSet = new HashSet<>(pageSize.intValue()); while (iterator.hasNext()) { couponMemberSet.add(iterator.next()); writeNum++; if (couponMemberSet.size() >= pageSize) { bufferedWriter.write(couponMemberSet.toString()); bufferedWriter.newLine(); bufferedWriter.flush(); writeLine++; couponMemberSet.clear(); } } if (CollectionUtils.isNotEmpty(couponMemberSet)) { bufferedWriter.write(couponMemberSet.toString()); bufferedWriter.newLine(); bufferedWriter.flush(); writeLine++; } } }
Mybatis是如何實現(xiàn)基于Cursor查詢的
com.mysql.cj.jdbc.result.ResultSetImpl實現(xiàn)類
ResultSetImpl 是mybatis中實現(xiàn)游標查詢結果解析的類。
這個實現(xiàn)類的next方法中調用了ResultsetRows接口的next方法。
ResultsetRows接口
ResultsetRows接口有ResultsetRowsCursor,ResultsetRowsStatic,ResultsetRowsStreaming三個實現(xiàn)類。
本文寫的游標查詢的場景,使用的是ResultsetRowsCursor這個實現(xiàn)類。
詳細看下ResultsetRowsCursor這個實現(xiàn)類,主要是實現(xiàn)了Iterator的hasNext和next方法,這也是使用Cursor獲取數(shù)據(jù)需要的兩個方法。
下面是hasnext方法的邏輯,根據(jù)下次要獲取的游標索引和當前本地數(shù)據(jù)集計算返回是否還有后續(xù)數(shù)據(jù)可以獲取。
下面是next方法的邏輯,先執(zhí)行一下hasnext的邏輯判斷,再取值
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
mysql之delete刪除記錄后數(shù)據(jù)庫大小不變
這篇文章主要介紹了mysql之delete刪除記錄后數(shù)據(jù)庫大小不變的相關資料,需要的朋友可以參考下2016-06-06完美解決MySQL通過localhost無法連接數(shù)據(jù)庫的問題
下面小編就為大家?guī)硪黄昝澜鉀QMySQL通過localhost無法連接數(shù)據(jù)庫的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02安裝MySQL在最后的start service停住了解決方法
今天為一個客戶配置服務器的時候,發(fā)現(xiàn)的問題,原來他自己安裝過mysql但安全沒有配置好,路徑選擇的也不好,重新安裝后發(fā)現(xiàn)在start service卡住了,通過下面的方法解決了,特分享下2013-11-11