最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

Mybatis流式查詢(xún)并將結(jié)果分批寫(xiě)入文件

    /**
     * 流式查詢(xún),全量導(dǎo)出
     *
     * @param req  查詢(xún)條件
     * @param size 單個(gè)文件數(shù)據(jù)最大條數(shù)
     * @return
     */
    @ApiOperation(value = "流式查詢(xún),全量導(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;
        //文件名稱(chēng)
        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á)式訪問(wèn)外部變量有一個(gè)非常重要的限制:變量不可變(只是引用不可變,而不是真正的不可變),AtomicInteger是一個(gè)提供原子操作的Integer類(lèi),通過(guò)線程安全的方式操作加減。
        //文件內(nèi)容行數(shù)
        AtomicInteger in = new AtomicInteger(1);
        //文件名稱(chēng)
        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è)定每次流式查詢(xún)的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使用流式查詢(xún)避免數(shù)據(jù)量過(guò)大導(dǎo)致OOM

本文已springboot項(xiàng)目為例,要實(shí)現(xiàn)流式查詢(xú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語(yǔ)句需要增加fetchSize屬性,底層是調(diào)用jdbc的setFetchSize方法,查詢(xún)時(shí)從結(jié)果集里面每次取設(shè)置的行數(shù),循環(huán)去取,直到取完。

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

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

自定義ResultHandler來(lái)分批處理結(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) {
? ? // 這里獲取流式查詢(xún)每次返回的單條結(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)用,用來(lái)完成最后一批數(shù)據(jù)處理
? public void end(){
? ? handle();// 處理最后一批不到BATCH_SIZE的數(shù)據(jù)
? }
}

serviceImpl類(lèi)中的使用

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é)

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

流式查詢(xún):內(nèi)存會(huì)保持穩(wěn)定,不會(huì)隨著記錄的增長(zhǎng)而增長(zhǎng)。其內(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)文章

最新評(píng)論

翁源县| 闵行区| 阳谷县| 甘洛县| 台江县| 乳山市| 东至县| 界首市| 凤凰县| 平陆县| 洪雅县| 宝兴县| 长丰县| 屏东县| 于田县| 米泉市| 安丘市| 吉木萨尔县| 桓台县| 黄大仙区| 兰坪| 新丰县| 渭源县| 辰溪县| 宁晋县| 驻马店市| 富川| 麦盖提县| 西乌珠穆沁旗| 新宁县| 柳河县| 贵阳市| 且末县| 兰考县| 隆林| 乌审旗| 丹阳市| 永州市| 凤翔县| 卢氏县| 朝阳区|