怎么解决在大型报表系统导出百万级数据时,未使用基于游标的 ResultHandler 导致的前置内存溢出

胖敏姑娘_4029

胖敏姑娘_4029

2026-05-25

907人浏览

原创

报表导出OOM主因是MyBatis默认全量加载百万级结果至List,应改用游标流式处理:声明ResultHandler或Cursor返回类型、XML配置fetchSize、禁用事务、驱动层启用useCursorFetch、Handler内禁止缓存。

怎么解决在大型报表系统导出百万级数据时,未使用基于游标的 resulthandler 导致的前置内存溢出

直接用 List 接收百万级查询结果,是报表导出 OOM 的最常见原因。MyBatis 默认把整张结果集缓存进内存再封装成 List,哪怕 SQL 很简单,只要数据量上去,JVM 堆立刻告急。解决的核心不是“怎么撑住”,而是“根本别让它进内存”——必须切换到基于游标的流式处理路径。

必须显式启用游标模式

Mapper 接口不能返回 List,必须声明为接收 ResultHandler 或 Cursor:

  • 错误写法:List selectAllOrders(); —— 全量加载,OOM 高发
  • 正确写法:void selectAllOrders(ResultHandler handler); 或 Cursor selectAllOrders();
  • XML 中对应 SQL 标签需加 @Options(resultSetType = FORWARD_ONLY, fetchSize = -2147483648)(MySQL)或 fetchSize="1000"(PostgreSQL/通用场景)

关闭事务与自动提交

Spring 的 @Transactional 会强制开启事务并自动 commit,导致 MyBatis 无法维持游标状态,底层 ResultSet 被提前关闭:

  • 导出接口上必须标注 @Transactional(propagation = Propagation.NOT_SUPPORTED)
  • 手动获取 SqlSession 时,调用 sqlSessionFactory.openSession(ExecutorType.SIMPLE, false),第二个参数 false 表示不自动 commit
  • 确认 Spring Boot 配置中 mybatis.configuration.default-executor-type=simple 已生效

驱动层必须配合流式参数

MyBatis 只是调度层,真正决定是否流式的是 JDBC 驱动。MySQL Connector/J 必须满足三个条件才启用流式传输:

  • 连接 URL 加参数:?useCursorFetch=true&defaultFetchSize=1000(注意 & 需转义)
  • 驱动版本 ≥ 5.1.38 或 ≥ 8.0.16(老版本会静默降级)
  • 执行后检查 ResultSet.getFetchSize() 是否返回 1000 或 Integer.MIN_VALUE,否则配置未生效

ResultHandler 内严禁缓存

流式的意义是“来一条、处理一条、丢一条”。任何在 handler 里 add() 到 ArrayList、HashMap 的行为,都等于回到全量加载的老路:

  • Excel 导出用 SXSSFWorkbook,每写 100 行调一次 row.flush()
  • CSV 导出用 BufferedWriter 直接写 OutputStream,编码设为 UTF-8
  • HTTP 响应流用 ResponseEntity.ok().body(new StreamingResponseBody() { ... }),在 lambda 里写 output,只 flush() 不 close()
PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
mybatis一级缓存和二级缓存
mybatis一级缓存和二级缓存

在MyBatis中,一级缓存和二级缓存是两种不同级别的缓存机制,它们都可以用来提高性能。本专题提供mybatis一级缓存和二级缓存相关文章,大家可以免费阅读。

2023.08.21

603

4

ibatis和mybatis有什么区别
ibatis和mybatis有什么区别

ibatis和mybatis的区别:1、基本信息不同;2、开发时间不同;3、功能与易用性;4、配置文件;5、入参类型与出参类型;6、返回结果集接受方式;7、语法差异;8、数据库方言支持;9、插件支持;10、社区活跃度;11、全球化支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

2962

5

mybatis如何配置数据库连接
mybatis如何配置数据库连接

mybatis配置数据库连接的方法:1、指定数据源;2、配置事务管理器;3、配置类型处理器和映射器;4、使用环境元素;5、配置别名。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

446

5

mybatis工作原理及流程是什么
mybatis工作原理及流程是什么

mybatis工作原理及流程:1、配置文件;2、接口与映射;3、sql解析与生成;4、执行计划;5、结果处理;6、动态sql;7、缓存机制;8、插件;9、事务管理;10、日志与监控;11、扩展性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

292

4

hibernate和mybatis有哪些区别
hibernate和mybatis有哪些区别

hibernate和mybatis的区别:1、实现方式;2、性能;3、对象管理的对比;4、缓存机制。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

302

5

Java MyBatis框架
Java MyBatis框架

本专题专注于Java主流ORM框架MyBatis的应用,系统讲解SQL映射、动态SQL、结果映射、分页查询、缓存机制与多表关联等核心内容,并结合企业管理系统、电商平台和后台管理项目实战,帮助学员全面掌握高效的数据库持久层开发技能。

2025.08.26

6369

22

Java I/O 与 NIO 编程体系合集
Java I/O 与 NIO 编程体系合集

全面讲解 Java I/O 编程的演进与核心 API,涵盖传统 I/O 的字节流(InputStream/OutputStream)与字符流(Reader/Writer)体系、装饰器模式在 I/O 中的应用(BufferedReader/InputStreamReader)、文件读写与目录操作、NIO 核心三要素(Buffer 缓冲区/Channel 通道/Selector 选择器)、ByteBuffer 操作与内存映射文件(Mappe

2026.04.29

492

28

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

2026.11.05

20

12

DBeaver安全防护教程大全
DBeaver安全防护教程大全

DBeaver安全防护专题,围绕数据库连接安全、账号密码保护和访问权限管理展开,整理SSL/TLS加密连接、SSH隧道、数据库凭据保存及证书验证等配置方法,同时介绍敏感信息保护、远程连接风险和高权限账号使用等注意事项,帮助用户提高数据库日常管理的安全性。

2026.11.05

20

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习