0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MyBatis流式查詢輕松幫你解決分頁慢的問題

5jek_harmonyos ? 來源:思否開發(fā)者社區(qū) ? 作者:捏造的信仰 ? 2021-08-04 15:52 ? 次閱讀

作者丨捏造的信仰

segmentfault.com/a/1190000022478915

Part1基本概念

流式查詢指的是查詢成功后不是返回一個(gè)集合而是返回一個(gè)迭代器,應(yīng)用每次從迭代器取一條查詢結(jié)果。流式查詢的好處是能夠降低內(nèi)存使用。

如果沒有流式查詢,我們想要從數(shù)據(jù)庫取 1000 萬條記錄而又沒有足夠的內(nèi)存時(shí),就不得不分頁查詢,而分頁查詢效率取決于表設(shè)計(jì),如果設(shè)計(jì)的不好,就無法執(zhí)行高效的分頁查詢。因此流式查詢是一個(gè)數(shù)據(jù)庫訪問框架必須具備的功能。

流式查詢的過程當(dāng)中,數(shù)據(jù)庫連接是保持打開狀態(tài)的,因此要注意的是:執(zhí)行一個(gè)流式查詢后,數(shù)據(jù)庫訪問框架就不負(fù)責(zé)關(guān)閉數(shù)據(jù)庫連接了,需要應(yīng)用在取完數(shù)據(jù)后自己關(guān)閉。

Part2MyBatis 流式查詢接口

MyBatis 提供了一個(gè)叫 org.apache.ibatis.cursor.Cursor 的接口類用于流式查詢,這個(gè)接口繼承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知:

Cursor 是可關(guān)閉的。實(shí)際上當(dāng)關(guān)閉 Cursor 時(shí),也一并將數(shù)據(jù)庫連接關(guān)閉了;

Cursor 是可遍歷的。

除此之外,Cursor 還提供了三個(gè)方法:

isOpen():用于在取數(shù)據(jù)之前判斷 Cursor 對(duì)象是否是打開狀態(tài)。只有當(dāng)打開時(shí) Cursor 才能取數(shù)據(jù);

isConsumed():用于判斷查詢結(jié)果是否全部取完;

getCurrentIndex():返回已經(jīng)獲取了多少條數(shù)據(jù)。

因?yàn)?Cursor 實(shí)現(xiàn)了迭代器接口,因此在實(shí)際使用當(dāng)中,從 Cursor 取數(shù)據(jù)非常簡單:

try(Cursor cursor = mapper.querySomeData()) {

cursor.forEach(rowObject -》 {

// 。。。

});

}

使用 try-resource 方式可以令 Cursor 自動(dòng)關(guān)閉。

Part3但構(gòu)建 Cursor 的過程不簡單

我們舉個(gè)實(shí)際例子。下面是一個(gè) Mapper 類:

@Mapper

public interface FooMapper {

@Select(“select * from foo limit #{limit}”)

Cursor《Foo》 scan(@Param(“l(fā)imit”) int limit);

}

方法 scan() 是一個(gè)非常簡單的查詢。我們在定義這個(gè)方時(shí),指定返回值為 Cursor 類型,MyBatis 就明白這個(gè)查詢方法是一個(gè)流式查詢。

然后我們再寫一個(gè) SpringMVC Controller 方法來調(diào)用 Mapper(無關(guān)的代碼已經(jīng)省略):

@GetMapping(“foo/scan/0/{limit}”)

public void scanFoo0(@PathVariable(“l(fā)imit”) int limit) throws Exception {

try (Cursor《Foo》 cursor = fooMapper.scan(limit)) { // 1

cursor.forEach(foo -》 {}); // 2

}

}

假設(shè) fooMapper 是 @Autowired 進(jìn)來的。注釋 1 處是獲取 Cursor 對(duì)象并保證它能最后關(guān)閉;2 處則是從 cursor 中取數(shù)據(jù)。

上面的代碼看上去沒什么問題,但是執(zhí)行 scanFoo0(int) 時(shí)會(huì)報(bào)錯(cuò):

java.lang.IllegalStateException: A Cursor is already closed.

這是因?yàn)槲覀兦懊嬲f了在取數(shù)據(jù)的過程中需要保持?jǐn)?shù)據(jù)庫連接,而 Mapper 方法通常在執(zhí)行完后連接就關(guān)閉了,因此 Cusor 也一并關(guān)閉了。

所以,解決這個(gè)問題的思路不復(fù)雜,保持?jǐn)?shù)據(jù)庫連接打開即可。我們至少有三種方案可選。

方案一:SqlSessionFactory

我們可以用 SqlSessionFactory 來手工打開數(shù)據(jù)庫連接,將 Controller 方法修改如下:

@GetMapping(“foo/scan/1/{limit}”)

public void scanFoo1(@PathVariable(“l(fā)imit”) int limit) throws Exception {

try (

SqlSession sqlSession = sqlSessionFactory.openSession(); // 1

Cursor《Foo》 cursor =

sqlSession.getMapper(FooMapper.class).scan(limit) // 2

) {

cursor.forEach(foo -》 { });

}

}

上面的代碼中,1 處我們開啟了一個(gè) SqlSession (實(shí)際上也代表了一個(gè)數(shù)據(jù)庫連接),并保證它最后能關(guān)閉;2 處我們使用 SqlSession 來獲得 Mapper 對(duì)象。這樣才能保證得到的 Cursor 對(duì)象是打開狀態(tài)的。

方案二:TransactionTemplate

在 Spring 中,我們可以用 TransactionTemplate 來執(zhí)行一個(gè)數(shù)據(jù)庫事務(wù),這個(gè)過程中數(shù)據(jù)庫連接同樣是打開的。代碼如下:

@GetMapping(“foo/scan/2/{limit}”)

public void scanFoo2(@PathVariable(“l(fā)imit”) int limit) throws Exception {

TransactionTemplate transactionTemplate =

new TransactionTemplate(transactionManager); // 1

transactionTemplate.execute(status -》 { // 2

try (Cursor《Foo》 cursor = fooMapper.scan(limit)) {

cursor.forEach(foo -》 { });

} catch (IOException e) {

e.printStackTrace();

}

return null;

});

}

上面的代碼中,1 處我們創(chuàng)建了一個(gè) TransactionTemplate 對(duì)象(此處 transactionManager 是怎么來的不用多解釋,本文假設(shè)讀者對(duì) Spring 數(shù)據(jù)庫事務(wù)的使用比較熟悉了),2 處執(zhí)行數(shù)據(jù)庫事務(wù),而數(shù)據(jù)庫事務(wù)的內(nèi)容則是調(diào)用 Mapper 對(duì)象的流式查詢。注意這里的 Mapper 對(duì)象無需通過 SqlSession 創(chuàng)建。

方案三:@Transactional 注解

這個(gè)本質(zhì)上和方案二一樣,代碼如下:

@GetMapping(“foo/scan/3/{limit}”)

@Transactional

public void scanFoo3(@PathVariable(“l(fā)imit”) int limit) throws Exception {

try (Cursor《Foo》 cursor = fooMapper.scan(limit)) {

cursor.forEach(foo -》 { });

}

}

它僅僅是在原來方法上面加了個(gè) @Transactional 注解。這個(gè)方案看上去最簡潔,但請注意 Spring 框架當(dāng)中注解使用的坑:只在外部調(diào)用時(shí)生效。在當(dāng)前類中調(diào)用這個(gè)方法,依舊會(huì)報(bào)錯(cuò)。

以上是三種實(shí)現(xiàn) MyBatis 流式查詢的方法。

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • mybatis
    +關(guān)注

    關(guān)注

    0

    文章

    63

    瀏覽量

    6779

原文標(biāo)題:還在擔(dān)心分頁慢嗎? MyBatis 流式查詢解決你的煩惱

文章出處:【微信號(hào):harmonyos_developer,微信公眾號(hào):harmonyos_developer】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    一臺(tái)“兩棲”的光譜流式分析儀----CytoFLEX mosaic

    上海2025年2月6日?/美通社/ -- 貝克曼庫爾特生命科學(xué)正式推出CytoFLEX家族新成員:CytoFLEX mosaic光譜流式分析儀 它是一款具備"兩棲"能力的流式
    的頭像 發(fā)表于 02-06 20:03 ?154次閱讀
    一臺(tái)“兩棲”的光譜<b class='flag-5'>流式</b>分析儀----CytoFLEX mosaic

    老舊小區(qū)充電樁限流式保護(hù)器的應(yīng)用

    摘要? ?隨著城市化進(jìn)程的推進(jìn),老舊小區(qū)的電氣設(shè)施逐漸顯現(xiàn)出無法滿足現(xiàn)代用電需求的局面。特別是在老舊小區(qū)進(jìn)行用電改造時(shí),電氣安全問題尤為突出。傳統(tǒng)的電氣保護(hù)設(shè)備在短路和過載保護(hù)方面存在響應(yīng)、壽命短
    的頭像 發(fā)表于 01-06 14:34 ?254次閱讀
    老舊小區(qū)充電樁限<b class='flag-5'>流式</b>保護(hù)器的應(yīng)用

    Mybatis 攔截器實(shí)現(xiàn)單數(shù)據(jù)源內(nèi)多數(shù)據(jù)庫切換

    作者:京東保險(xiǎn) 王奕龍 物流的分揀業(yè)務(wù)在某些分揀場地只有一個(gè)數(shù)據(jù)源,因?yàn)閿?shù)據(jù)量比較大,將所有數(shù)據(jù)存在一張表內(nèi)查詢速度,也為了做不同設(shè)備數(shù)據(jù)的分庫管理,便在這個(gè)數(shù)據(jù)源內(nèi)創(chuàng)建了多個(gè)不同庫名但表完全相同
    的頭像 發(fā)表于 12-12 10:23 ?996次閱讀

    什么是虛擬內(nèi)存分頁 Windows系統(tǒng)虛擬內(nèi)存優(yōu)化方法

    虛擬內(nèi)存分頁概述 在Windows操作系統(tǒng)中,虛擬內(nèi)存是通過分頁機(jī)制實(shí)現(xiàn)的。分頁允許系統(tǒng)將內(nèi)存中的數(shù)據(jù)移動(dòng)到硬盤上,以便為當(dāng)前運(yùn)行的程序騰出空間。這個(gè)過程對(duì)于保持系統(tǒng)的流暢運(yùn)行至關(guān)重要,尤其是在物理
    的頭像 發(fā)表于 12-04 09:16 ?819次閱讀

    Simplelink? CC3220-OV788音頻/視頻流式傳輸參考

    電子發(fā)燒友網(wǎng)站提供《Simplelink? CC3220-OV788音頻/視頻流式傳輸參考.pdf》資料免費(fèi)下載
    發(fā)表于 09-02 11:13 ?0次下載
    Simplelink? CC3220-OV788音頻/視頻<b class='flag-5'>流式</b>傳輸參考

    滑動(dòng)變阻器限流式分壓式接法區(qū)別

    滑動(dòng)變阻器是一種常見的電子元件,用于調(diào)節(jié)電路中的電阻值。在實(shí)際應(yīng)用中,滑動(dòng)變阻器的接法主要有兩種:限流式和分壓式。這兩種接法在電路設(shè)計(jì)和應(yīng)用中有著不同的優(yōu)缺點(diǎn)和適用范圍。 一、限流式接法 工作原理
    的頭像 發(fā)表于 08-05 14:37 ?4773次閱讀

    流式滑動(dòng)變阻器的選型原則

    流式滑動(dòng)變阻器,又稱為限流電阻器或限流電位器,是一種用于限制電路中電流大小的電子元件。在電子電路設(shè)計(jì)中,選擇合適的限流式滑動(dòng)變阻器對(duì)于確保電路的穩(wěn)定運(yùn)行和提高電路性能至關(guān)重要。 一、限流式滑動(dòng)
    的頭像 發(fā)表于 08-05 14:31 ?1228次閱讀

    使用mybatis切片實(shí)現(xiàn)數(shù)據(jù)權(quán)限控制

    一、使用方式 數(shù)據(jù)權(quán)限控制需要對(duì)查詢出的數(shù)據(jù)進(jìn)行篩選,對(duì)業(yè)務(wù)入侵最少的方式就是利用mybatis或者數(shù)據(jù)庫連接池的切片對(duì)已有業(yè)務(wù)的sql進(jìn)行修改。切片邏輯完成后,僅需要在業(yè)務(wù)中加入少量標(biāo)記代碼
    的頭像 發(fā)表于 07-09 17:26 ?510次閱讀
    使用<b class='flag-5'>mybatis</b>切片實(shí)現(xiàn)數(shù)據(jù)權(quán)限控制

    流式繼電器工作特性有哪些

    流式繼電器是一種利用整流原理實(shí)現(xiàn)繼電器觸點(diǎn)切換的電子元件,廣泛應(yīng)用于電力系統(tǒng)、工業(yè)自動(dòng)化、通信設(shè)備等領(lǐng)域。 整流式繼電器的工作原理 整流式繼電器的工作原理基于整流原理。當(dāng)輸入電壓達(dá)到一定值
    的頭像 發(fā)表于 06-28 10:26 ?1004次閱讀

    流式繼電器輸入的是什么電源

    流式繼電器是一種常見的電氣元件,廣泛應(yīng)用于電力系統(tǒng)、工業(yè)自動(dòng)化、通信設(shè)備等領(lǐng)域。它的核心功能是將輸入的交流電源轉(zhuǎn)換為直流電源,以驅(qū)動(dòng)繼電器的線圈,實(shí)現(xiàn)對(duì)電路的控制。本文將詳細(xì)介紹整流式繼電器
    的頭像 發(fā)表于 06-28 10:21 ?1014次閱讀

    流式繼電器與無極繼電器的區(qū)別

    在電氣工程和自動(dòng)化領(lǐng)域,繼電器是一種非常重要的控制元件。繼電器的主要作用是接收輸入信號(hào),然后根據(jù)輸入信號(hào)的狀態(tài)來控制輸出電路的通斷。根據(jù)其工作原理和結(jié)構(gòu)特點(diǎn),繼電器可以分為很多種類,其中整流式繼電器
    的頭像 發(fā)表于 06-28 10:17 ?1421次閱讀

    流式繼電器結(jié)構(gòu)上有哪些特點(diǎn)

    流式繼電器是一種利用整流原理來實(shí)現(xiàn)繼電器動(dòng)作的電氣設(shè)備,廣泛應(yīng)用于電力系統(tǒng)、工業(yè)自動(dòng)化、通信設(shè)備等領(lǐng)域。本文將詳細(xì)介紹整流式繼電器的結(jié)構(gòu)特點(diǎn),包括其工作原理、主要組成部分、性能指標(biāo)、應(yīng)用場景等方面
    的頭像 發(fā)表于 06-28 10:15 ?1294次閱讀

    流式繼電器屬于什么繼電器

    流式繼電器是一種特殊類型的繼電器,它主要用于將交流電轉(zhuǎn)換為直流電。這種繼電器在許多應(yīng)用中都非常重要,例如在電力系統(tǒng)中,它可以用于控制和保護(hù)設(shè)備。在本文中,我們將詳細(xì)介紹整流式繼電器的工作原理、類型
    的頭像 發(fā)表于 06-28 10:07 ?1003次閱讀

    分庫分表后復(fù)雜查詢的應(yīng)對(duì)之道:基于DTS實(shí)時(shí)性ES寬表構(gòu)建技術(shù)實(shí)踐

    分表,通過分庫分表應(yīng)對(duì)存系統(tǒng)讀寫性能瓶頸和存儲(chǔ)瓶頸;分庫分表幫我們解決問題的同時(shí),也帶來了復(fù)雜性;比如多條件的分頁查詢,多條件的聯(lián)表查詢變得復(fù)雜起來,通過調(diào)研我們發(fā)現(xiàn)針對(duì)這些分頁,聯(lián)表
    的頭像 發(fā)表于 06-25 18:30 ?1028次閱讀
    分庫分表后復(fù)雜<b class='flag-5'>查詢</b>的應(yīng)對(duì)之道:基于DTS實(shí)時(shí)性ES寬表構(gòu)建技術(shù)實(shí)踐

    影響電動(dòng)汽車交流充時(shí)間的因素有哪些?

    影響電動(dòng)汽車交流充時(shí)間的因素有哪些? 電動(dòng)汽車的充時(shí)間受到多個(gè)因素的影響。下面將詳細(xì)介紹這些因素,并解釋它們是如何影響充時(shí)間的。 首先,電動(dòng)汽車的充時(shí)間受到電動(dòng)汽車電池的容量的
    的頭像 發(fā)表于 04-08 16:13 ?1506次閱讀