欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mybatis流式查詢并實(shí)現(xiàn)將結(jié)果分批寫入文件

 更新時(shí)間:2023年08月11日 10:01:29   作者:isTrueLoveColour  
這篇文章主要介紹了Mybatis流式查詢并實(shí)現(xiàn)將結(jié)果分批寫入文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Mybatis流式查詢并將結(jié)果分批寫入文件

    /**
     * 流式查詢,全量導(dǎo)出
     *
     * @param req  查詢條件
     * @param size 單個(gè)文件數(shù)據(jù)最大條數(shù)
     * @return
     */
    @ApiOperation(value = "流式查詢,全量導(dǎo)出")
    @GetMapping("/streamAll")
    public BaseResultModel streamAll(ReqBillRecordBackQuery req, Integer size) {
        try {
            billRecordBackService.streamAll(req, size);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return BaseResultModel.success();
    }

以xml的方式

 @Override
    @Transactional
    public void streamAll(ReqBillRecordBackQuery req, Integer size) throws Exception {
        exportXml(req,size);
    }
    private void exportXml(ReqBillRecordBackQuery req, Integer size) throws Exception{
        //文件內(nèi)容行數(shù)
        Integer in = 0;
        //文件名稱
        Integer fileName=0;
        String name = "exportTest";
        String suf =".txt";
        String path = "H:\\新建文件夾\\新建文件夾\\export\\";
        File ff = new File(path);
        //遞歸刪除目錄中的所有文件和子目錄,而不刪除目錄本身。
        FileUtils.cleanDirectory(ff);
        File fe = new File(path+name+fileName+suf);
        //刪除此抽象路徑名表示的文件或目錄
        //mkdirs()可以建立多級(jí)文件夾, mkdir()只會(huì)建立一級(jí)的文件夾
//        fe.mkdirs();
        //獲取文件輸出列
        BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter(fe));
        StringBuilder sb = new StringBuilder();
        Cursor<BillRecordBack> billRecordBacks = mapper.streamAll(req);
        for (BillRecordBack bil : billRecordBacks) {
            sb.append(bil).append("\n");
            in++;
            if (in>=size){
                in=0;
                fileName++;
                fe = new File(path+name+fileName+suf);
                bufferedWriter = new BufferedWriter(new FileWriter(fe));
            }
            bufferedWriter.write(sb.toString());
            //將StringBuilder數(shù)據(jù)重置
            sb.setLength(0);
        }
        //最后需要自己關(guān)閉流
        billRecordBacks.close();
        bufferedWriter.close();
    }
    <select id="streamAll" resultType="com.psh.hik.entity.BillRecordBack" fetchSize="5000">
        select t_id,r_id,r_time,r_number,descd,deleted,ctime,crname,mtime,chname from  bill_record_back
        <where>
            <if test="null != param.rTime and ''!= param.rTime">
              ctime = #{param.rTime}
            </if>
            <if test="null != param.rNumber and ''!= param.rNumber">
                ctime = #{param.rNumber}
            </if>
        </where>
    </select>

以mybatis-plus的方式

    private void exportNote(ReqBillRecordBackQuery req, Integer size) throws Exception{
        //lambda表達(dá)式訪問外部變量有一個(gè)非常重要的限制:變量不可變(只是引用不可變,而不是真正的不可變),AtomicInteger是一個(gè)提供原子操作的Integer類,通過線程安全的方式操作加減。
        //文件內(nèi)容行數(shù)
        AtomicInteger in = new AtomicInteger(1);
        //文件名稱
        AtomicInteger fileName= new AtomicInteger(0);
        String name = "exportTest";
        String suf =".txt";
        String path = "H:\\新建文件夾\\新建文件夾\\export\\";
        File ff = new File(path);
        //遞歸刪除目錄中的所有文件和子目錄,而不刪除目錄本身。
        FileUtils.cleanDirectory(ff);
        AtomicReference<File> fe = new AtomicReference<>(new File(path + name + fileName + suf));
        AtomicReference<BufferedWriter> bufferedWriter= new AtomicReference<>(new BufferedWriter(new FileWriter(fe.get())));
        StringBuilder sb = new StringBuilder();
        mapper.exportNote(req,resultContext -> {
            try {
                if (fileName.get()>=20){
                    return;
                }
                BillRecordBack resultObject = resultContext.getResultObject();
                sb.append(resultObject).append("\n");
                //a.incrementAndGet(); 先+1,再返回,a.getAndIncrement()先返回,再 +1
                in.getAndIncrement();
                System.out.println(in);
                if (in.get() >=size){
                    in.set(0);
                    fileName.getAndIncrement();
                    fe.set(new File(path + name + fileName + suf));
                    bufferedWriter.set(new BufferedWriter(new FileWriter(fe.get())));
                }
                bufferedWriter.get().write(sb.toString());
                //將StringBuilder數(shù)據(jù)重置
                sb.setLength(0);
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        });
        bufferedWriter.get().close();
    }
    @Select("select t_id,r_id,r_time,r_number,descd,deleted,ctime,crname,mtime,chname from  bill_record_back")
    //這個(gè)注解是設(shè)定每次流式查詢的iterator大小的,這里是1000條 ,ResultSetType.FORWARD_ONLY 只允許游標(biāo)向下移動(dòng)
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 5000)
    @ResultType(BillRecordBack.class)
    void exportNote(ReqBillRecordBackQuery req, ResultHandler<BillRecordBack> handler);

Mybatis使用流式查詢避免數(shù)據(jù)量過大導(dǎo)致OOM

本文已springboot項(xiàng)目為例,要實(shí)現(xiàn)流式查詢需要完成以下幾步

POM文件中的配置

springboot中整合mybatis

<dependency>
? <groupId>org.mybatis.spring.boot</groupId>
? <artifactId>mybatis-spring-boot-starter</artifactId>
? <version>1.1.1</version>
</dependency>

mapper.xml文件配置

select語句需要增加fetchSize屬性,底層是調(diào)用jdbc的setFetchSize方法,查詢時(shí)從結(jié)果集里面每次取設(shè)置的行數(shù),循環(huán)去取,直到取完。

默認(rèn)size是0,也就是默認(rèn)會(huì)一次性把結(jié)果集的數(shù)據(jù)全部取出來,當(dāng)結(jié)果集數(shù)據(jù)量很大時(shí)就容易造成內(nèi)存溢出。

<select id="selectGxids" resultType="java.lang.String" fetchSize="1000">
? ?SELECT gxid from t_gxid
?</select>

自定義ResultHandler來分批處理結(jié)果集

package flowselect;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import java.util.Set;
public class GxidResultHandler implements ResultHandler<String> {
? // 這是每批處理的大小
? private final static int BATCH_SIZE = 1000;
? private int size;
? // 存儲(chǔ)每批數(shù)據(jù)的臨時(shí)容器
? private Set<String> gxids;
? public void handleResult(ResultContext<? extends String> resultContext) {
? ? // 這里獲取流式查詢每次返回的單條結(jié)果
? ? String gxid = resultContext.getResultObject();
? ? // 你可以看自己的項(xiàng)目需要分批進(jìn)行處理或者單個(gè)處理,這里以分批處理為例
? ? gxids.add(gxid);
? ? size++;
? ? if (size == BATCH_SIZE) {
? ? ? handle();
? ? }
? }
? private void handle() {
? ? try {
? ? ? // 在這里可以對(duì)你獲取到的批量結(jié)果數(shù)據(jù)進(jìn)行需要的業(yè)務(wù)處理
? ? } finally {
? ? ? // 處理完每批數(shù)據(jù)后后將臨時(shí)清空
? ? ? size = 0;
? ? ? gxids.clear();
? ? }
? }
? // 這個(gè)方法給外面調(diào)用,用來完成最后一批數(shù)據(jù)處理
? public void end(){
? ? handle();// 處理最后一批不到BATCH_SIZE的數(shù)據(jù)
? }
}

serviceImpl類中的使用

package flowselect;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class ServiceImpl implements Service {
? @Autowired
? SqlSessionTemplate sqlSessionTemplate;
? public void method(){
? ? GxidResultHandler gxidResultHandler = new GxidResultHandler();
? ? sqlSessionTemplate.select("flowselect.Mapper.selectGxids", gxidResultHandler);
? ? gxidResultHandler.end();
? }
}

總結(jié)

非流式查詢:內(nèi)存會(huì)隨著查詢記錄的增長而近乎直線增長。

流式查詢:內(nèi)存會(huì)保持穩(wěn)定,不會(huì)隨著記錄的增長而增長。其內(nèi)存大小取決于批處理大小BATCH_SIZE的設(shè)置,該尺寸越大,內(nèi)存會(huì)越大。所以BATCH_SIZE應(yīng)該根據(jù)業(yè)務(wù)情況設(shè)置合適的大小。

另外要切記每次處理完一批結(jié)果要記得釋放存儲(chǔ)每批數(shù)據(jù)的臨時(shí)容器,即上文中的gxids.clear();

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 淺談web服務(wù)器項(xiàng)目中靜態(tài)請(qǐng)求和動(dòng)態(tài)請(qǐng)求處理

    淺談web服務(wù)器項(xiàng)目中靜態(tài)請(qǐng)求和動(dòng)態(tài)請(qǐng)求處理

    這篇文章主要介紹了淺談web服務(wù)器項(xiàng)目中靜態(tài)請(qǐng)求和動(dòng)態(tài)請(qǐng)求處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java遞歸遍歷樹形結(jié)構(gòu)的實(shí)現(xiàn)代碼

    Java遞歸遍歷樹形結(jié)構(gòu)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java遞歸遍歷樹形結(jié)構(gòu)的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2016-03-03
  • Spring中的@ExceptionHandler異常攔截器

    Spring中的@ExceptionHandler異常攔截器

    這篇文章主要介紹了Spring中的@ExceptionHandler異常攔截器,Spring的@ExceptionHandler可以用來統(tǒng)一處理方法拋出的異常,給方法加上@ExceptionHandler注解,這個(gè)方法就會(huì)處理類中其他方法拋出的異常,需要的朋友可以參考下
    2024-01-01
  • MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn)

    MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn)

    本文主要介紹了MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn),主要包括單個(gè)參數(shù)傳遞綁定,序號(hào)參數(shù)傳遞綁定,注解參數(shù)傳遞綁定,pojo(對(duì)象)參數(shù)傳遞綁定,map參數(shù)傳遞綁定這幾種類型,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12
  • 淺析mybatis和spring整合的實(shí)現(xiàn)過程

    淺析mybatis和spring整合的實(shí)現(xiàn)過程

    據(jù)官方的說法,在Mybatis3問世之前,Spring3的開發(fā)工作就已經(jīng)完成了,所以Spring3中還是沒有對(duì)Mybatis3的支持。因此由Mybatis社區(qū)自己開發(fā)了一個(gè)Mybatis-Spring用來滿足Mybatis用戶整合Spring的需求,下面通過Mybatis-Spring來整合Mybatis跟Spring的用法做介紹
    2015-10-10
  • java驗(yàn)證碼組件kaptcha使用方法

    java驗(yàn)證碼組件kaptcha使用方法

    這篇文章主要介紹了java驗(yàn)證碼組件kaptcha使用方法,很不錯(cuò)的一個(gè)組件,可以在JAVA開發(fā)中使用,大家都試試吧
    2013-11-11
  • Java中的PowerMock使用實(shí)踐

    Java中的PowerMock使用實(shí)踐

    這篇文章主要介紹了Java中的PowerMock使用實(shí)踐,@PrepareForTest和@RunWith是成對(duì)出現(xiàn)的,一般@RunWith(PowerMockRunner.class),@PrepareForTest的值是引用的靜態(tài)方法或私有方法的類,需要的朋友可以參考下
    2023-12-12
  • springboot整合minio的超詳細(xì)教程

    springboot整合minio的超詳細(xì)教程

    在很多互聯(lián)網(wǎng)產(chǎn)品應(yīng)用中,都涉及到各種與文件存儲(chǔ)相關(guān)的業(yè)務(wù),隨著技術(shù)的發(fā)展,關(guān)于如何解決分布式文件存儲(chǔ)也有了比較成熟的方案,比如私有云部署下可以考慮fastdfs,阿里云對(duì)象存儲(chǔ)oss,七牛云等,本篇將為你介紹另一種文件存儲(chǔ)方式,即MinIO,需要的朋友可以參考下
    2023-12-12
  • Spring Boot 快速集成 Redis的方法

    Spring Boot 快速集成 Redis的方法

    這篇文章主要介紹了Spring Boot 如何快速集成 Redis,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • IntelliJ IDEA創(chuàng)建普通的Java 項(xiàng)目及創(chuàng)建 Java 文件并運(yùn)行的教程

    IntelliJ IDEA創(chuàng)建普通的Java 項(xiàng)目及創(chuàng)建 Java 文件并運(yùn)行的教程

    這篇文章主要介紹了IntelliJ IDEA創(chuàng)建普通的Java 項(xiàng)目及創(chuàng)建 Java 文件并運(yùn)行的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02

最新評(píng)論