Mybatis-plus 大数据量数据流式查询通用接口

声明:
大数据流查询解决查询结果集过大的导致内存溢出的问题。
针对查询通用SQL与数据交互的次数加到数据库压力,要使用预编译。

一、案例需求

查询sys_user表中的所有数据,数据库中供3条数据,在实际处理类中我设置了具体处理批次的数量为2条数据为一个批次,那么一个批次就只处理2条数据,处理完成后,继续处理下一个批次(2条数据),直至全部处理完成。

大病项目案例:数据库查询1次查询数量为1000条,在实际的逻辑处理中,我设置了本次批次处理的数据数量为500条,那一个批次就只处理500条,处理完第1个批次500条后,在处理下一次批次的500条。

注:

  1. 这个根据实际情况动态设置
  2. 项目中默认1000条查询数据库一次(开发者可忽略)

设计初衷:
为了让大家都按照规范去做,因此抽象此接口,具体实现类去继承,获取对应的实体对象,然后一一获取里面的对象。

局限性:
当在一个类中获取的对象不只是一个,此抽象接口不能使用,需要单独的在自己的实现类中,按照此方式手写对用的mapper,待补充

二、使用案例:
2.1. 自定义查询接口

声明接口作用:只是为了听过一个接口供外部调用服务

package com.gblfy.ly.service;

public interface ISDQueryResulService {

    public void batchSDHandle();
}

在这里插入图片描述
注:如果外部不需要调用,此接口可以省略,实现类可不实现此接口

2.2. 逻辑处理类
  • 1>继承extends SDQueryResultHandler重新handle方法,实现自己定义的接口
  • 2>注入SDQueryWrapper接口
    案例处理类路径:
com.gblfy.ly.service.impl. SDQueryResulServiceImpl

如下图所示:
在这里插入图片描述

2.3. 调用案例
1.自定义SQL语句
2.new 本身逻辑处理类
3.设置具体处理的批次数据数量
4.new 好的处理类变量名,放到此方法内部
5.调用lastSDHandle方法

注:具体使用请参考,案例代码,已上传gitlab仓库

在这里插入图片描述

2.4. 具体逻辑处理案例

声明:查询批次的结果集最终返回的数据是一个list,大家只需要对list中的数据进行循环遍历,根据key获取处理对应的value即可。
在这里插入图片描述

三、企业案例

参数获取方式:根据key获取value,简言之,查询出来的数据放到了map中。

3.1. key名称获取
  1. 找到此类com.gblfy.ly.config. SDQueryResultHandler
  2. 在31行和32行打上断点
  3. debug启动项目
  4. url请求http://localhost/batchSDHandle
  5. 进项目,断点跳到32行

所有的key和value就都展示了出来
如下图所示:

在这里插入图片描述

3.2. 逻辑类测试

在com.gblfy.ly.service.impl. SDQueryResulServiceImpl类的35行打上断点,满足一个批次的数量就会跳到handle此方法中
在这里插入图片描述
在这里插入图片描述
注:数据库一共5条数据。

3.3.最后一个批次处理方案

从开始到结束,按照批次依次执行到最后一个批次,会自动调用lastSDHandle方法,因此,我们只需要处理好handle()方法即可。
最后,把获取的数据进行处理根据实际需求自行处理。
在这里插入图片描述

四、 通用SQL预编译处理
4.1. 业务场景

相同SQL和数据库交互多次,请按照规范适应预编译处理。

4.2. xml形式

在xml文件中添加statementType="PREPARED"即属性可
在这里插入图片描述

4.3. 注解形式
statementType = StatementType.PREPARED

在这里插入图片描述

五、企业案例
5.1. sql语句
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL COMMENT '主键ID',
  `name` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `email` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '邮箱',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'Jone', '18', 'test1@baomidou.com');
INSERT INTO `user` VALUES ('2', 'Jack', '20', 'test2@baomidou.com');
INSERT INTO `user` VALUES ('3', 'Tom', '28', 'test3@baomidou.com');
INSERT INTO `user` VALUES ('4', 'Sandy', '21', 'test4@baomidou.com');
INSERT INTO `user` VALUES ('5', 'Billie', '24', 'test5@baomidou.com');
5.2. 大数据流查询接口
package com.gblfy.ly.mapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.gblfy.ly.entity.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.session.ResultHandler;

import java.util.Map;

/**
 * 处理流数据的公用接口
 *
 * @author gblfy
 * @date 2020-11-18
 */
@Mapper
public interface SDQueryWrapper {

    /**
     * ResultSetType.FORWARD_ONLY 表示游标只向前滚动
     * fetchSize 每次查询數量
     * @ResultTyp 定义返回的对象类型
     *
     * @param sql  SQL語句
     * @param handler  返回处理数据对象
     */
    @Select("${sql}")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000)
    @ResultType(Map.class)
    void streamDataDynamicHandle(@Param("sql") String sql, ResultHandler<Map> handler);

    @Select("${sql}")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 2)
    @ResultType(User.class)
    void dynamicSelectLargeData1(@Param("sql") String sql, ResultHandler<User> handler);

    @Select("select * from user t ${ew.customSqlSegment}")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000,statementType = StatementType.PREPARED)
    @ResultType(User.class)
    void getOrgWithBigData(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper, ResultHandler<User> handler);
}
5.3. 大数据查询结果集处理抽象类
package com.gblfy.ly.config;

import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 大数据查询结果集处理抽象类
 *
 * @author gblfy
 * @date 2020-11-18
 */
public abstract class SDQueryResultHandler implements ResultHandler<Map> {

    private final static Logger logger = LoggerFactory.getLogger(SDQueryResultHandler.class);

    // 这是每一个批处理查询的数量
    public  int batchSize = 1000;
    //初始值
    public int size=0;
    // 存储每批数据的临时容器
    public List<Map> list = new ArrayList<Map>();

    public void handleResult(ResultContext<? extends Map> resultContext) {
        // 这里获取流式查询每次返回的单条结果
        Map map = resultContext.getResultObject();
        list.add(map);
        size++;
        if (size == batchSize) {
            logger.info("本批次处理数据量 :{}",size );
            handle();
        }
    }
     // 1.这个方需要子类重写此接口,处理具体业务逻辑
    public abstract void handle();

    //处理最后一批不到 batchSize(查询设定的阀值)的数据
    public void lastSDHandle() {
        logger.info("最后批次处理数据量 :{}",size );
        handle();
    }

    public void setBatchSize(int batchSize) {
        this.batchSize = batchSize;
    }
}
5.4. 服务接口
package com.gblfy.ly.service;

public interface ISDQueryResulService {

    public void batchSDHandle();
}
5.5. 服务接口实现类
package com.gblfy.ly.service.impl;

import com.gblfy.ly.config.SDQueryResultHandler;
import com.gblfy.ly.mapper.SDQueryWrapper;
import com.gblfy.ly.service.ISDQueryResulService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class SDQueryResulServiceImpl extends SDQueryResultHandler implements ISDQueryResulService {

    private final static Logger logger = LoggerFactory.getLogger(SDQueryResulServiceImpl.class);

    @Resource
    private SDQueryWrapper sdQueryWrapper;

    @Override
    public void batchSDHandle() {
        String sql = "select * from user";
        SDQueryResulServiceImpl sdQueryResulService = new SDQueryResulServiceImpl();

        sdQueryResulService.setBatchSize(2);//批量处理数据量  根据实际情况设置
        //1.按批次处理查询结果集数据
        sdQueryWrapper.streamDataDynamicHandle(sql,sdQueryResulService);
        //2.处理最后一个批次的查询结果数据
        sdQueryResulService.lastSDHandle();
    }

    // 在这里可以对你获取到的批量结果数据进行需要的业务处理
    @Override
    public void handle() {
        try {
            logger.info("---------------------:{}",list.size());
            //list 批量查询结果集,对此list进行业务处理
            for (int i = 0; i < list.size(); i++) {
                logger.info("---------------------:{}",list.get(i).get("name"));
            }
        } finally {
            // 处理完每批数据后后将临时清空
            size = 0;
            list.clear();
        }
    }
}
5.6. 前端控制器
package com.gblfy.ly.controller;

import com.gblfy.ly.service.ISDQueryResulService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SDQueryResultController {

    @Autowired
    private ISDQueryResulService isdQueryResulService;


    @GetMapping("/batchSDHandle")
    public void batchSDHandle() {
        isdQueryResulService.batchSDHandle();
    }
}
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gblfy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值