Mybatis游標(biāo)查詢大量數(shù)據(jù)方式
Mybatis游標(biāo)查詢大量數(shù)據(jù)
對(duì)大量數(shù)據(jù)進(jìn)行處理時(shí),為防止內(nèi)存泄漏情況發(fā)生,所以采用mybatis plus游標(biāo)方式進(jìn)行數(shù)據(jù)查詢處理,當(dāng)查詢百萬(wàn)級(jí)的數(shù)據(jù)的時(shí)候,使用游標(biāo)可以節(jié)省內(nèi)存的消耗,不需要一次性取出所有數(shù)據(jù),可以進(jìn)行逐條處理或逐條取出部分批量處理
mapper層
- 使用Cursor類型進(jìn)行數(shù)據(jù)接收
- @Options,fetchSize設(shè)置為Integer最小值
- @Select,寫查詢sql
@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE) @Select("select domain from illegal_domain where icpstatus != #{icpstatus}") Cursor<IllegalDomain> getDayJobDomain(@Param("icpstatus") Integer icpstatus);
service層
Cursor<IllegalDomain> domainList = illegalDomainMapper.getDayJobDomain(1);
數(shù)據(jù)處理
forEach方式
domainList.forEach(illegalDomain -> { ? ? //處理邏輯,根據(jù)業(yè)務(wù)需求自行完成 ? ? Future<IcpStatusVo> future = checkIcpThreadPool.submit(new IcpCheckThread(illegalDomain.getDomain(), configMap)); ? ? results.add(future); });
迭代器
Iterator<IllegalDomain> iter = domainList.iterator(); while (iter.hasNext()) { ? ? <!--// Fetch next 10 employees--> ? ? <!--for(int i = 0; i<10 && iter.hasNext(); i++) {--> ? ? <!-- ? ?smallChunk.add(iter.next());--> ? ? <!--}--> ? ?? ? ? //處理邏輯,根據(jù)業(yè)務(wù)需求自行完成 ? ? Future<IcpStatusVo> future = checkIcpThreadPool.submit(new IcpCheckThread(illegalDomain.getDomain(), configMap)); ? ? results.add(future); }
資源釋放
使用完畢后,在finally塊釋放資源,否則游標(biāo)不關(guān)閉也可能會(huì)導(dǎo)致內(nèi)存溢出問(wèn)題
try{ ? ? //your code ? ?? } catch (Exception e) { ? ? log.error(e); } finally { ? ? if(null != domainList){ ? ? ? ? try { ? ? ? ? ? ? domainList.close(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } }
Mybatis游標(biāo)使用總結(jié)
當(dāng)查詢百萬(wàn)級(jí)的數(shù)據(jù)的時(shí)候,查詢出所有數(shù)據(jù)并放入內(nèi)存中時(shí)會(huì)發(fā)生OOM(OutOfMemoryException),使用游標(biāo)可以節(jié)省內(nèi)存的消耗,不需要一次性取出所有數(shù)據(jù),可以進(jìn)行逐條處理或逐條取出部分批量處理,在此場(chǎng)景下就可以使用游標(biāo)的概念來(lái)解決這個(gè)問(wèn)題。
什么是游標(biāo)
游標(biāo)(Cursor)是處理數(shù)據(jù)的一種方法,為了查看或者處理結(jié)果集中的數(shù)據(jù),游標(biāo)提供了在結(jié)果集中一次一行或者多行前進(jìn)或向后瀏覽數(shù)據(jù)的能力。
Demo:
// 第一種 @Options(resultSetType = ResultSetType.FORWARD_ONLY) @Select("SELECT * FROM department WHERE status = 0") List<DepartmentEntity> queryDepartmentAll(); // 第二種 在Mybatis-3.4.0版本中,不支持@select注解,在3.4.1版本中已經(jīng)修復(fù): @Options(resultSetType = ResultSetType.FORWARD_ONLY) @Select("SELECT * FROM department WHERE status = 0") Cursor<Employee> cursorQueryDepartmentAll();
@Service public class DepartmentServiceImpl implements DepartmentService { private static final Logger LOG = LoggerFactory.getLogger(DepartmentServiceImpl.class); @Autowired private DepartmentDao departmentDao; @Autowired private SqlSessionTemplate sqlSessionTemplate; public List<DepartmentDTO> getDepartmentList(DepartmentSearchParam param) { Cursor<Object> cursor = null; SqlSession sqlSession = null; try { sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(); cursor = sqlSession.selectCursor(DepartmentDao.class.getName() + ".queryDepartmentAll"); cursor.forEach(e -> { // 處理邏輯 }); // 也可以使用迭代器:Iterator<Object> iterator = cursor.iterator(); } catch (Exception e) { e.printStackTrace(); } finally { if (null != cursor) { try { cursor.close(); } catch (Exception e) { LOG.error(e.getMessage(), e); } } if (null != sqlSession) { try { sqlSession.close(); } catch (Exception e) { LOG.error(e.getMessage(), e); } } } } }
ResultSet.TYPE_FORWORD_ONLY
結(jié)果集的游標(biāo)只能向下滾動(dòng)。ResultSet.TYPE_SCROLL_INSENSITIVE
結(jié)果集的游標(biāo)可以上下移動(dòng),當(dāng)數(shù)據(jù)庫(kù)變化時(shí),當(dāng)前結(jié)果集不變。ResultSet.TYPE_SCROLL_SENSITIVE
返回可滾動(dòng)的結(jié)果集,當(dāng)數(shù)據(jù)庫(kù)變化時(shí),當(dāng)前結(jié)果集同步改變。
注意:游標(biāo)是可以前后移動(dòng)的。如果resultSetType = TYPE_SCROLL_INSENSITIVE ,就是設(shè)置游標(biāo)就可以前后移動(dòng)。
Mybatis為了保證可以前后移動(dòng),Mybatis會(huì)把之前查詢的數(shù)據(jù)一直保存在內(nèi)存中。
所以并不能根本解決OOM,所以我們這里需要設(shè)置為@Options(resultSetType = ResultSetType.FORWARD_ONLY)(其實(shí)默認(rèn)就是ResultSetType.FORWARD_ONLY)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Mybatis集成MySQL使用游標(biāo)查詢處理大批量數(shù)據(jù)方式
- MyBatis游標(biāo)Cursor在Oracle數(shù)據(jù)庫(kù)上的測(cè)試方式
- Mybatis中的游標(biāo)查詢Cursor(滾動(dòng)查詢)
- mybatis如何對(duì)大量數(shù)據(jù)的游標(biāo)查詢
- MyBatis游標(biāo)Cursor的正確使用和百萬(wàn)數(shù)據(jù)傳輸?shù)膬?nèi)存測(cè)試
- java使用mybatis調(diào)用存儲(chǔ)過(guò)程返回一個(gè)游標(biāo)結(jié)果集方式
相關(guān)文章
解決spring mvc 多數(shù)據(jù)源切換,不支持事務(wù)控制的問(wèn)題
下面小編就為大家?guī)?lái)一篇解決spring mvc 多數(shù)據(jù)源切換,不支持事務(wù)控制的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Java Http請(qǐng)求傳json數(shù)據(jù)亂碼問(wèn)題的解決
這篇文章主要介紹了Java Http請(qǐng)求傳json數(shù)據(jù)亂碼問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09springMvc和mybatis-plus中枚舉值和字段的映射
這篇文章主要為大家介紹了springMvc和mybatis-plus中枚舉值和字段的映射示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Java實(shí)現(xiàn)在不同線程中運(yùn)行的代碼實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)在不同線程中運(yùn)行的代碼,結(jié)合具體實(shí)例形式分析了java多線程操作的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-04-04手把手教你搭建第一個(gè)Spring Batch項(xiàng)目的步驟
這篇文章主要介紹了手把手教你搭建第一個(gè)Spring Batch項(xiàng)目的步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09線程池ThreadPoolExecutor并行處理實(shí)現(xiàn)代碼
這篇文章主要介紹了線程池ThreadPoolExecutor并行處理實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Java語(yǔ)言----三種循環(huán)語(yǔ)句的區(qū)別介紹
下面小編就為大家?guī)?lái)一篇Java語(yǔ)言----三種循環(huán)語(yǔ)句的區(qū)別介紹。小編舉得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07