SpringBoot+MyBatis实现百万级数据的导出

SpringBoot 实现 MySQL 百万级数据量导出并避免 OOM 的解决方案! 动态数据导出是一般项目都会涉及到的功能。它的基本实现逻辑就是从mysql查询数据,加载到内存,然后从内存创建excel或者csv,以流的形式响应给前端。参考:https://grokonez.com/spring-framework/spring-boot/excel-file-download-from-springboot-restapi-apache-poi-mysql。SpringBoot下载excel基本都是这么干。 阅读详情

MyBatis导出多量数据时,需要设置成stream模式,一条一条导出。

先定义一个工具类DownloadProcessor,它内部封装一个HttpServletResponse对象,用来将对象写入到csv。

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description
 * @Author Bernie
 * @Date 2023/4/7 16:51
 **/
public class DownloadProcessor {

    private final HttpServletResponse response;

    public DownloadProcessor(HttpServletResponse response) {
        this.response = response;
        String fileName = System.currentTimeMillis() + ".csv";
        this.response.addHeader("Content-Type", "application/csv");
        this.response.addHeader("Content-Disposition", "attachment; filename="+fileName);
        this.response.setCharacterEncoding("UTF-8");
    }

    public <E> void processData(E record) {
        try {
            response.getWriter().write(record.toString()); //如果是要写入csv,需要重写toString,属性通过","分割
            response.getWriter().write("\n");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

然后通过实现org.apache.ibatis.session.ResultHandler里面的handleResult方法,自定义我们的ResultHandler,它用于获取java对象,然后传递给上面的DownloadProcessor处理类进行写文件操作:

import com.fang.demo.entity.DO.TestExport;
import com.fang.demo.utils.DownloadProcessor;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;

/**
 * @Description
 * @Author Bernie
 * @Date 2023/4/7 16:53
 **/
public class CustomResultHandler implements ResultHandler {

    private final DownloadProcessor downloadProcessor;

    public CustomResultHandler(DownloadProcessor downloadProcessor) {
        super();
        this.downloadProcessor = downloadProcessor;
    }

    @Override
    public void handleResult(ResultContext resultContext) {
        TestExport authors = (TestExport) resultContext.getResultObject();
        downloadProcessor.processData(authors);
    }
}

测试实体类

import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Description
 * @Author Bernie
 * @Date 2023/4/7 14:17
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestExport {

    @TableId(value = "table_id")
    private String tableId;
    private String name;
    private String age;
    private String id;

}

Mapper接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fang.demo.entity.DO.TestExport;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @Description
 * @Author Bernie
 * @Date 2023/4/7 14:41
 **/
@Mapper
@Repository
public interface TestExportMapper extends BaseMapper<TestExport> {	       
    //example对象没有使用,放这里是告诉你们如果需要按条件查找需要怎么做
    List<TestExport> streamByExample(TestExport example); //以stream形式从mysql获取数据,
}

Mapper xml文件核心片段
在stream获取数据的方式中多了一条属性: fetchSize=“-2147483648”
查了一下官方文档,应该是设置成数据无限吧
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fang.demo.mapper.TestExportMapper">
    <select id="streamByExample" fetchSize="-2147483648" resultType="com.fang.demo.entity.DO.TestExport">
        SELECT table_id,name,age,id FROM test_export ORDER BY table_id DESC
    </select>
</mapper>

接下里就是常写的controlle和service了

import com.fang.demo.handle.CustomResultHandler;
import com.fang.demo.mapper.TestExportMapper;
import com.fang.demo.utils.DownloadProcessor;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description
 * @Author Bernie
 * @Date 2023/4/7 17:05
 **/
@Service
public class DownloadServiceImpl {

    @Autowired
    private  SqlSessionTemplate sqlSessionTemplate;
    @Autowired
    private  TestExportMapper testExportMapper;

    /**
     * stream读数据写文件方式
     * @param httpServletResponse
     * @throws IOException
     */
    public void streamDownload(HttpServletResponse httpServletResponse) throws IOException {
        CustomResultHandler customResultHandler = new CustomResultHandler(new DownloadProcessor(httpServletResponse));
        sqlSessionTemplate.select(
                "com.fang.demo.mapper.TestExportMapper.streamByExample", null, customResultHandler);//具体到哪个mapper的哪个方法,参数和handler处理方法
        httpServletResponse.getWriter().flush();
        httpServletResponse.getWriter().close();
    }

}
import com.fang.demo.service.DownloadServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description
 * @Author Bernie
 * @Date 2023/4/6 15:49
 **/
@RestController
public class TestController {
    @Autowired
    private DownloadServiceImpl downloadService;

   @GetMapping("streamDownload")
    public void streamDownload(HttpServletResponse response) throws IOException {
        downloadService.streamDownload(response);
    }
}

程序就此完成,测试

保证数据库有数据,如果没有,先写入200百万条数据

先执行以下函数:

DELIMITER $$
DROP FUNCTION IF EXISTS `mock_data`$$
CREATE FUNCTION mock_data ()
BEGIN
 DECLARE num INT DEFAULT 2000000;
 DECLARE i INT DEFAULT 0;
 WHILE i<num DO
  INSERT INTO `test_export`(`name`,`age`,`id`)VALUES(CONCAT('zhangsan',i),RAND() * (99 - 10) + 10,i);
  SET i=i+1;
 END WHILE;
 RETURN i;
END
DELIMITER ;

再执行

select mock_data();

跑个1分多钟,写入2百万条数据。即可测试

参考链接:直达

SpringBoot项目实战:一个注解搞定EasyExcel流式导出,MyBatis配置避坑指南 本文详细介绍了如何在SpringBoot项目中通过注解驱动实现EasyExcel流式导出,并结合MyBatis流式查询优化配置,解决大数据量导出时的性能瓶颈问题。文章提供了完整的代码示例和性能对比数据,帮助开发者高效实现低内存占用的Excel导出功能。 阅读详情

相关推荐

SpringBoot+MyBatis流式查询vs游标查询:大数据量处理方案选型指南

本文深入探讨了SpringBoot+MyBatis在大数据量处理中的流式查询与游标查询方案。通过对比分析两种技术的原理、实现方式及性能表现,提供了针对不同场景的选型指南,帮助开发者高效处理百万级数据,避免内存溢出和性能瓶颈。重点解析了fetchSize参数配置、事务控制等关键优化点。

1a2s3d4f5g的博客 914

springboot + mybatis 流式查询

springboot + mybatis 流式查询

S_L__的博客 1233

Java实现百万级数据从Excel导入到数据库

在一个后台管理功能中,Excel导入数据是不可缺少,但是当处理大数据量的Excel文件导入时候就可能会带来一些列的问题,本文我们会分析问题产生的原因。并提供解决方案以及完整的实现代码。

小徐的博客 6776

Mybatis实现百万级数据导出(重点代码摘要)

MyBatis 实现逐条获取数据,必须要自定义 ResultHandler,然后在 mapper.xml 文件中,对应的 select 语句中添加 fetchSize=“-2147483648”。最后将自定义的 ResultHandler 传给 SqlSession 来执行查询,并将返回的结果进行处理。

moernagedian的博客 849

使用Spring Boot和Mybatis Plus整合EasyExcel实现Excel文件的批量导入和导出

本文介绍了如何使用Spring Boot和Mybatis Plus整合EasyExcel来实现Excel文件的批量导入和导出功能。通过编写相应的Controller和监听器类,可以方便地处理Excel数据,并将其与数据库进行交互。在许多应用程序中,需要从Excel文件中批量导入数据到数据库,并且有时还需要将数据库中的数据导出为Excel文件。方法用于查询数据库中的数据,并将其导出为Excel文件。使用Spring Boot和Mybatis Plus整合EasyExcel实现Excel文件的批量导入和导出。

HackLogic的博客 491

智能垃圾桶改造指南:树莓派+垃圾分类模型部署全记录(含数据集获取)

本文提供了一份详尽的智能垃圾桶DIY改造指南,核心是利用树莓派部署轻量化的YOLOv8垃圾分类模型。内容涵盖从数据集获取、模型训练与OpenVINO量化优化,到硬件组装、电路连接及软件集成的全流程,旨在帮助创客和爱好者以低成本实现一个能自动识别垃圾并分类的AIoT原型系统。

k6l7m8n9的博客 509

使用mybatis的流式查询进行大数据量的导出csv文件

前提: 1.要进行百万级数据的导出 2.导出格式为csv文件 首先需要导入依赖 <!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv --> <dependency> <groupId>net.sourceforge.javacsv</groupId> <artifactId>ja

大白的成长之路 3370

BES平台集成第三方音频算法避坑指南:以声加ENC为例,聊聊文件放置、内存分配与授权那些事

本文详细解析了在BES平台上集成声加ENC降噪算法的全流程,包括技术选型、系统架构设计、内存管理及量产授权等关键环节。特别针对BES平台的双核架构和内存限制,提供了文件放置、内存分配与授权验证的实用解决方案,帮助开发者高效实现音频算法集成。

weixin_33720956的博客 514

使用Mybatis Stream 模式 优化大数据量查询和导出

背景 特定查询条件下测试数据量 70w (查询条件优化并命中了组合索引),group by 聚合后 3w 条数据,并进行导出为Excel 1. 查询数据库 select * from xxx group by user where create_date BETWEEN ‘’ AND ‘’ 1.1 分页查询 假如分页大小为 1000, 需要执行 30 次SQL才能得到所有数据。 此时MySQL扫描的行数是 70w * 30 = 2100w。 由于 group by 使用了中间表,当分页执行到尾声,性能下降特

Myth的博客 4245

T12 电烙铁简单程序逻辑

通过分析就可以知道,发热丝本身即是发热体,也是热偶的工作端。怎么可能是热电动势呢,确实,但不要忘了T12-OUTPUT端的电压是PWM波,理论上是有单片机PWM电压为0 v时的,而T12-OUTPUT端的电压此时也应为0。在T12烙铁头中,PID控制算法通过监测温度传感器的输出,计算当前温度与设定温度之间的差异,并根据这一差异调节加热功率,以实现烙铁头温度的精确控制。这段代码实现了一个简单的增量式PID控制器,通过计算当前温度与期望温度之间的差异以及历史偏差值,调节输出控制量,实现对温度的精确控制。

hgkhjkljnl的博客 1万+

Pikachu靶场环境搭建(Windows环境下安装详细教程)

Pikachu靶场是一个漏洞测试练习平台。其中包含了常见的web安全漏洞,如果你是一个渗透测试学习者没有靶场的练手,那么pikachu是一个很好的测试平台。

weixin_42857656的博客 1823

SpringBoot 实现 MySQL 百万级数据量导出并避免 OOM 的解决方案

点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 10:33更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2021超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数据库中间件 Sharding-JDBC 和 MyCAT 源码解析作业调度中间件 E...

芋艿V 325

Unity+Hybridclr发布WebGL记录

问题不多,比预想中的顺利,如果遇到问题建议先看Hybridclr的常见问题里面有没有解决方案,没遇到Hybridclr的报错,所以记录的问题里面没有Hybridclr相关的。导出设置里的压缩格式选择了Brotli,而服务器或浏览器不支持,据说是可以拓展服务器配置使支持Brotli,但是由于我本人是IIS小白,所以换了种压缩格式,在publishing Settings修改Compression Fromat为Gzip。3.在浏览器运行之后视图一直闪烁。,修改配置,这个网上很常见。

a598211757的博客 1037

Spring Boot 究竟如何实现百万级数据量从 MySQL 导出,还能避免内存溢出?

/** * 导出数据到文件 * * @param fileName 导出文件名 * @param pageSize 每页数据条数 */ public void exportToFile(String fileName, int pageSize) throws IOException { File file = new File(fileName);这时候,我们可以将数据分区导出,每个线程只处理一部分数据,从而提高导出性能。

Reische的博客 960

微信小程序 - 实现身份证OCR识别人像面与国徽面并提取字段信息,详解从手机相册选取或打开摄像头拍照上传身份证正反面图片ocr文字识别数据填充表单(提供免费纯前端ocr识别插件+百度OCR识别API)

微信小程序身份证识别,微信小程序身份证拍照、上传并OCR识别,微信小程序实现OCR扫描识别,微信小程序识别身份证免费插件,微信小程序实现身份证识别功能。ocr识别插件。微信身份证拍照后进行ocr识别,微信小程序OCR扫描识别身份证,OCR身份证实名认证+图片上传+拍照上传图片,微信小程序之身份证照片正反上传,小程序OCR身份证识别,微信小程序实现文字识别-ocr插件,微信小程序利用百度AI实现扫描身份证获取信息功能,基于微信小程序OCR插件实现身份证拍照、上传并OCR识别的示例demo,将上传的照片传到服务

🏆 前端领域优质创作者 8133

【深度学习|多实例学习】多实例学习(Multiple Instance Learning, MIL)的起源、发展和应用,附代码(一)

【深度学习|多实例学习】多实例学习(Multiple Instance Learning, MIL)的起源、发展和应用,附代码(一)

2401_89898861的博客 1921

CTO:给我一个SpringBoot实现MySQL百万级数据量导出并避免OOM的解决方案

动态数据导出是一般项目都会涉及到的功能。它的基本实现逻辑就是从mysql查询数据,加载到内存,然后从内存创建excel或者csv,以流的形式响应给前端。参考:https://grokonez.com/spring-framework/spring-boot/excel-file-download-from-springboot-restapi-apache-poi-mysql。SpringBoot下载excel基本都是这么干。

Javatutouhouduan的博客 924

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

SpringBoot + MySQL + EasyExcel 实现百万级数据报表自动化导出

下面给你一套✅ 解决​✅ 支持​✅ 适合。

wtoxk12的博客 412

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

SpringBoot + Mybaits 处理百万数据,内存溢出?不存在的!

springboot + mybaits 对数据库进行百万级别大数据量读取,并对这些数据进行操作,应用能顶得住吗?

weixin_43379487的博客 2773

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Java+EasyExcel 打造学习平台视频学习时长统计系统

本文介绍了一个基于Java17和SpringBoot3.2.5构建的在线教育平台视频学习时长统计系统。该系统通过"定时上报+关键节点上报"策略采集学生学习数据,结合快进检测、暂停排除等规则计算有效时长,支持按用户、课程、班级等多维度统计。系统采用Redis缓存热点数据提升查询性能,使用EasyExcel实现大数据量报表导出,并通过"实时统计+定时全量统计"双机制确保数据准确性。

果酱 の 博客 1815

避免 OOM,高效导出百万级数据的 SpringBoot 实现方案

动态数据导出是一般项目都会涉及到的功能。它的基本实现逻辑就是从mysql查询数据,加载到内存,然后从内存创建excel或者csv,以流的形式响应给前端。参考:https://grokonez.com/spring-framework/spring-boot/excel-file-download-from-springboot-restapi-apache-poi-mysql。SpringBoot下载excel基本都是这么干。

竹林幽深 532
上一篇: SpringBoot项目模块化开发-打包
下一篇: git pull因为代码冲突报错解决办法
凉白开º
博客等级 码龄8年 899粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值