公司的日报任务每天半夜 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()) 遍历....
SpringBoot + 批处理分片 + 分布式协调:千万级数据分片并行处理,避免单点瓶颈
引言 最近在处理一个用户数据迁移项目时,遇到了一个棘手的问题:需要将千万级的用户数据从旧系统迁移到新系统。如果用传统的单线程批处理方式,预计需要几天时间才能完成,而且一旦某个环节出错,整个迁移过程就得重来。 有没有一种方式能让批处理任务像分布式系统一样,把大任务拆分成小任务并行处理呢?答案是肯定的,今天就来聊聊SpringBoot如何通过批处理分片和分布式协调来解决千万级数据处理的性能瓶颈问题。 为什么需要批处理分片? 传统批处理的痛点 让我们先看看传统批处理方式的局限性: 单点处理瓶颈: // 传统的单线程批处理 @Service public class UserDataMigrationService { public void migrateAllUsers() { List<User> allUsers = userMapper.selectAllUsers(); // 1000万条数据 for (User user : allUsers) { // 逐条处理,耗时巨大 processUser(user); } } } 这种处理方式存在明显问题: 处理时间长 ....
SpringBoot + 批处理 + 失败重试队列:百万级数据批量导入,断点续传不丢数据
今天咱们聊聊一个在数据处理场景中非常关键的话题:大规模数据批量导入。 批量导入的痛点 在我们的日常开发工作中,经常会遇到这样的场景: 需要导入百万级用户数据,单次处理导致内存溢出 导入过程中发生异常,全部数据丢失需要重新开始 部分数据格式错误,整个导入任务失败 导入进度不可控,无法实时监控处理状态 传统的批量导入方式要么一次性加载所有数据导致内存问题,要么容错能力差,一旦出错就需要从头再来。今天我们就来聊聊如何用Spring Boot批处理构建一个健壮的批量数据导入系统。 为什么选择Spring Batch 相比传统的批量处理方案,Spring Batch有以下优势: 分块处理:支持数据分块处理,避免内存溢出 事务管理:精细的事务控制,确保数据一致性 容错机制:内置重试和跳过机制 监控支持:丰富的执行监控和统计信息 解决方案思路 今天我们要解决的,就是如何用Spring Boot + Spring Batch构建一个支持断点续传的批量数据导入系统。 核心思路是: 分块处理:将大数据集分成小块逐步处理 失败重试:建立失败数据重试队列 断点续传:记录处理进度,支持从中断点继续 数....
