Spring Batch 秒级处理百万级数据,内存占用降低95%
Excel导入一次吃掉8G内存,服务器当场卡死,老板在群里连发十个感叹号
把百万行Excel塞进数据库,90%的程序员第一反应是POI。
一次读完整个文件,内存飙到几个G,GC疯狂回收,CPU原地打转。
现场演示:20万行用户表,PoiItemReader直接吃掉7.8G,换成流式读取,瞬间降到380M,差距95%。
Spring Batch官方扩展包spring-batch-excel里藏着两个Reader。
PoiItemReader功能全,公式、样式都能识别,代价是把整张表一次性搬进内存。
StreamingXlsxItemReader只保留当前行,读完就扔,内存曲线像跳楼机。
代价是公式、合并单元格、富文本全部失效,数据必须干净。
真实项目踩坑记录:某电商大促,凌晨三点运营甩过来一个300M的订单文件。
老代码用PoiItemReader,启动5分钟后容器被K8s直接Kill。
临时改流式,十分钟跑完,内存峰值不到400M。
血的教训:文件超过50M就别用POI全家桶。
RowMapper写法也得换。
PoiItemReader给的是RowSet,能按列名取值。
StreamingXlsxItemReader只给String[],下标从0开始,表头得自己跳过。
代码少写一行,线上就多一次ArrayIndexOutOfBounds。
Chunk大小别乱调。
原文示例给10,实测20万行数据,chunk=1000时吞吐量最高,内存还能再省10%。
再大就适得其反,一次提交太多,数据库反而扛不住。
经验值:单行数据小于1K,chunk给500到2000之间最稳。
Job参数记得带时间戳。
同一个文件跑两次,Spring Batch默认当成同一个任务直接跳过。
加一行LocalDateTime.now(),每次启动都是新任务。
别问怎么知道的,运维凌晨四点电话吵醒的。
最后留一个思考题:如果Excel里混着图片、合并单元格、公式,流式读取全废,怎么办?
答案在评论区。