java千万级数据处理需结合spring batch的chunk(每批1000条批量写入)与partitioning(按id范围分20区并行),配jdbcpagingitemreader流式读取、超时控制、skip/retry及redis去重,确保高效稳定。

Java 项目中处理千万级数据,不能靠单线程逐条读写,必须结合 Spring Batch 的分块(Chunk)和分区(Partitioning)双层机制——前者解决“批量提交”,后者解决“并行加速”。核心不是堆配置,而是把数据切得合理、事务控得住、资源用得稳。
用 Chunk 实现每批 1000 条聚合写入
千万级数据若每条单独调第三方接口或执行 SQL,网络/数据库开销会爆炸。Spring Batch 的 chunk 模式天然支持 List 批量传递,关键在 ItemWriter 要接收 List,而不是单个对象:
- 配置 chunk size(如 1000),Step 中明确声明:
.<user user>chunk(1000)</user> - 自定义 ItemWriter 实现
ItemWriter<list>></list>,内部调用批量 HTTP 客户端(如 RestTemplate.exchange() 批量 POST)或 JDBC batchUpdate - 避免在 ItemProcessor 中做聚合逻辑——它只负责单条转换;聚合、组装、批量发送必须放在 Writer 阶段
用 Partitioner 切分数据源实现并行处理
光靠 chunk 只能串行处理,要真正提速,必须把千万条数据拆成多个独立子集,让多线程同时跑。前提是数据源支持范围查询(如主键 ID 连续):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 写一个 RangePartitioner:根据总记录数(如 1000 万)和预设分区数(如 20),算出每个分区的
minId和maxId,存入 ExecutionContext - Worker Step 的 Reader 必须是 @StepScope,通过 @Value("#{stepExecutionContext['minId']}") 动态拼 WHERE 条件,例如
WHERE id BETWEEN :minId AND :maxId - 用 TaskExecutorPartitionHandler 管理线程池,corePoolSize 建议设为 CPU 核心数(如 8),避免过度争抢数据库连接
读取阶段防内存溢出的关键配置
千万条记录不能全加载进内存,Reader 必须流式或分页拉取:
- 优先用
JdbcPagingItemReader(非 Cursor),配合 MySQL 的 LIMIT/OFFSET 或 Oracle 的 ROW_NUMBER(),每次只查一页 - 若已集成 MyBatis,可用 PageHelper + 自定义 Reader:在 read() 方法里调用
PageHelper.startPage(pageNum, pageSize),再查 Mapper 接口 - 禁用 JpaPagingItemReader(易触发 N+1 和全表扫描),也慎用 JdbcCursorItemReader(依赖 JDBC 游标,某些数据库驱动不稳)
生产环境必须加的稳定性保障
千万级任务一旦失败,重跑成本极高,需从设计上规避常见崩点:
- 每个 Chunk 设置合理超时(
transactionTimeout),防止长事务锁表;建议搭配isolation=ISOLATION_READ_COMMITTED - 开启 skip 和 retry:对脏数据跳过(如字段为空)、对网络抖动重试(如 HTTP 503 最多重试 3 次)
- 写入前加校验缓存(如 Redis BloomFilter),避免重复写入;写入后记录 checkpoint(如最后成功 ID 到 DB),支持断点续跑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










