国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

MyBatis流式查詢(xún)的三種實(shí)現方法

發(fā)布時(shí)間:2021-07-05 18:40 來(lái)源:腳本之家 閱讀:0 作者:碼農架構 欄目: 開(kāi)發(fā)技術(shù)

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

如果沒(méi)有流式查詢(xún),我們想要從數據取 1000 萬(wàn)條記錄而又沒(méi)有足夠的內存時(shí),就不得不分頁(yè)查詢(xún),而分頁(yè)查詢(xún)效率取決于表設計,如果設計的不好,就無(wú)法執行高效的分頁(yè)查詢(xún)。因此流式查詢(xún)是一個(gè)數據庫訪(fǎng)問(wèn)框架必須具備的功能。
流式查詢(xún)的過(guò)程當中,數據庫連接是保持打開(kāi)狀態(tài)的,因此要注意的是:執行一個(gè)流式查詢(xún)后,數據庫訪(fǎng)問(wèn)框架就不負責關(guān)閉數據庫連接了,需要應用在取完數據后自己關(guān)閉。

MyBatis 流式查詢(xún)接口

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

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

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

  • isOpen():用于在取數據之前判斷 Cursor 對象是否是打開(kāi)狀態(tài)。只有當打開(kāi)時(shí) Cursor 才能取數據;
  • isConsumed():用于判斷查詢(xún)結果是否全部取完;
  • getCurrentIndex():返回已經(jīng)獲取了多少條數據。

因為 Cursor 實(shí)現了迭代器接口,因此在實(shí)際使用當中,從 Cursor 取數據非常簡(jiǎn)單:

try(Cursor cursor = mapper.querySomeData()) {
    cursor.forEach(rowObject -> {
        // ...
    });
}

使用 try-resource 方式可以令 Cursor 自動(dòng)關(guān)閉。
但構建 Cursor 的過(guò)程不簡(jiǎn)單
我們舉個(gè)實(shí)際例子。下面是一個(gè) Mapper 類(lèi):

@Mapper
public interface FooMapper {
    @Select("select * from foo limit #{limit}")
    Cursor<Foo> scan(@Param("limit") int limit);
}

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

然后我們再寫(xiě)一個(gè) SpringMVC Controller 方法來(lái)調用 Mapper(無(wú)關(guān)的代碼已經(jīng)省略):

@GetMapping("foo/scan/0/{limit}")
public void scanFoo0(@PathVariable("limit") int limit) throws Exception {
    try (Cursor<Foo> cursor = fooMapper.scan(limit)) {  // 1
        cursor.forEach(foo -> {});                      // 2
    }
}

假設 fooMapper 是 @Autowired 進(jìn)來(lái)的。注釋 1 處是獲取 Cursor 對象并保證它能最后關(guān)閉;2 處則是從 cursor 中取數據。
上面的代碼看上去沒(méi)什么問(wèn)題,但是執行scanFoo0(int)時(shí)會(huì )報錯:

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

這是因為我們前面說(shuō)了在取數據的過(guò)程中需要保持數據庫連接,而 Mapper 方法通常在執行完后連接就關(guān)閉了,因此 Cusor 也一并關(guān)閉了。
所以,解決這個(gè)問(wèn)題的思路不復雜,保持數據庫連接打開(kāi)即可。我們至少有三種方案可選。

方案一:SqlSessionFactory

我們可以用 SqlSessionFactory 來(lái)手工打開(kāi)數據庫連接,將 Controller 方法修改如下:

@GetMapping("foo/scan/1/{limit}")
public void scanFoo1(@PathVariable("limit") int limit) throws Exception {
    try (
        SqlSession sqlSession = sqlSessionFactory.openSession();  // 1
        Cursor<Foo> cursor = 
              sqlSession.getMapper(FooMapper.class).scan(limit)   // 2
    ) {
        cursor.forEach(foo -> { });
    }
}

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

方案二:TransactionTemplate

在 Spring 中,我們可以用 TransactionTemplate 來(lái)執行一個(gè)數據庫事務(wù),這個(gè)過(guò)程中數據庫連接同樣是打開(kāi)的。代碼如下:

@GetMapping("foo/scan/2/{limit}")
public void scanFoo2(@PathVariable("limit") 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 對象(此處 transactionManager 是怎么來(lái)的不用多解釋?zhuān)疚募僭O讀者對 Spring 數據庫事務(wù)的使用比較熟悉了),2 處執行數據庫事務(wù),而數據庫事務(wù)的內容則是調用 Mapper 對象的流式查詢(xún)。注意這里的 Mapper 對象無(wú)需通過(guò) SqlSession 創(chuàng )建。

方案三:@Transactional 注解

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

@GetMapping("foo/scan/3/{limit}")
@Transactional
public void scanFoo3(@PathVariable("limit") int limit) throws Exception {
    try (Cursor<Foo> cursor = fooMapper.scan(limit)) {
        cursor.forEach(foo -> { });
    }
}

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

到此這篇關(guān)于MyBatis流式查詢(xún)的實(shí)現方法的文章就介紹到這了,更多相關(guān)MyBatis流式查詢(xún)內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

精品成在人线AV无码免费看| 久久精品中文字幕大胸| 99精产国品一二三产区区别| 国产成人精品日本亚洲77上位| 欧美男同GV免费网站观看| 中文字幕人乱码中文字幕|