公司的日报任务每天半夜 2 点跑,统计前一天所有订单的销售额。代码逻辑很简单——SELECT * FROM orders WHERE date = '2026-06-30',然后 for 循环逐条累加。平时几万条订单没问题,大促那天 300 万条订单,SELECT * 把 300 万行全部加载到了 JVM 堆里,直接 OOM。运维半夜被电话叫醒,手动分批 SQL 跑了一个小时才完成。 批处理的 OOM 跟文件下载的 OOM 原因一样——把全部数据一把梭进内存。 数据库能存那么大的表,不代表你的 JVM 堆能装下它。今天聊聊三种让批处理不再 OOM 的方法:流式查询、分片处理、游标分批提交。 问题:JDBC 默认是一次性加载全部结果集 MySQL 的 JDBC 驱动默认行为是:执行 SELECT 后,把所有结果行都拉到客户端内存里。你的代码写的虽然是 while (rs.next()),但在 next() 之前,数据已经在内存里了。 JDBC 默认行为: → 执行 SELECT → 100 万行全部加载到 ResultSet(JVM 堆) → while (rs.next()) 遍历....
