核心是流式写入+分批拉取+内存隔离:采用游标分页(主键/时间戳)替代offset,MyBatis设fetchSize=1000禁用缓存,EasyExcel直接向OutputStream写入OOXML流,每批write后自动flush,配合try-with-resources和finish()确保资源释放,异步化导出任务并存至对象存储。

核心是“流式写入 + 分批拉取 + 内存隔离”,不把全量数据或完整Excel结构加载进JVM堆。
分页查询:源头控量,避免一次性加载
数据库层必须用游标分页(非 offset/limit),防止深分页性能坍塌和内存堆积:
- 以主键或时间戳为游标,每次查 5000–10000 行,例如:
WHERE create_time > ? ORDER BY create_time LIMIT 10000 - MyBatis 中显式设置
fetchSize="1000",驱动层启用流式 ResultSet,避免 JDBC 缓存整结果集 - 禁用 ORM 二级缓存,关闭实体懒加载代理,只查导出所需字段(DTO 投影)
流式写入:边读边写,跳过内存 Workbook 对象
不构建 XSSFWorkbook 或完整 DOM 树,而是直接向 OutputStream 写入 OOXML 流:
- EasyExcel 底层封装 SXSSF,调用
EasyExcel.write(outputStream)即走纯流式路径,无中间 Workbook 实例 - 每批数据调用
writer.write(dataList, writeSheet)后,内部自动 flush 行到临时 ZIP 条目,内存仅保留当前批次对象 - 若需更高可控性,可基于 POI 5.2+ 的
StreamingWorkbook(实验性)或手动用ZipOutputStream拼接xl/worksheets/sheet1.xml
资源与生命周期管理:及时释放,防止泄漏
流、临时文件、连接等必须显式回收,尤其在异常分支中:
立即学习“Java免费学习笔记(深入)”;
- ExcelWriter 必须
finish(),否则底层临时文件不清理,磁盘空间持续增长 - 使用 try-with-resources 包裹 OutputStream,确保 HTTP 响应流或文件流被关闭
- 禁用 EasyExcel 自动列宽计算(
SimpleWriteHandler)、样式强引用、表头重复解析等默认开销项
异步解耦:脱离请求线程,提升稳定性
百万级导出不应阻塞 Web 容器线程,需服务端异步化:
- 前端提交导出请求后,立即返回任务 ID;后端用线程池或消息队列(如 RabbitMQ/Kafka)触发导出任务
- 导出完成将文件存至对象存储(OSS/S3)或 FTP,返回可下载 URL,避免大文件直传压垮 Tomcat/Nginx
- 配合任务状态轮询或 WebSocket 推送进度,用户端不卡死


















