spring boot中用spring batch做大批量数据迁移,关键在于稳、快、可追溯:需通过chunk分块(如commit-interval=1000)控内存与事务,用分片(partitioning)并行处理,配置skip/retry容错,持久化jobrepository元数据,关闭自动启动,结合xxl-job调度与step监听器实现全程可观测。

在 Spring Boot 中用 Spring Batch 做大批量数据迁移,关键不是“能不能跑通”,而是“怎么稳、快、可追溯”。核心在于合理拆解任务边界、控制内存压力、保障事务一致性,并配合外部调度与监控。下面从实操角度说清楚几个关键环节。
明确迁移任务结构:Job + Step + 三组件闭环
一个典型的数据迁移 Job 至少包含一个 Step,每个 Step 必须由 ItemReader → ItemProcessor → ItemWriter 构成:
-
ItemReader:从源库(如旧 MySQL 表)分页读取数据,推荐用
JdbcCursorItemReader或JdbcPagingItemReader,避免一次性加载全量;若源是文件(CSV/Excel),可用FlatFileItemReader配合自定义LineMapper - ItemProcessor:做字段映射、空值处理、业务规则校验(如状态转换、编码补全)、去重过滤等;建议轻量处理,耗时逻辑尽量后移或异步化
-
ItemWriter:写入目标库(如 Doris、新 PostgreSQL 表),使用
JdbcBatchItemWriter并设置chunk-size(如 2000),利用 JDBC 批量插入提升吞吐;注意目标表主键/唯一约束是否兼容,必要时先清空或加 ON CONFLICT 处理
控制资源与稳定性:分块、分片、失败策略
百万级迁移不能靠“一把梭”,必须分而治之:
-
Chunk 机制:在 Step 配置中指定
commit-interval="1000",每处理 1000 条提交一次事务,防止单事务过大导致锁表或 OOM -
分片(Partitioning):对主键或时间字段做范围切分(如 id BETWEEN ? AND ?),启动多个线程并行执行子 Step;需搭配
MultiResourcePartitioner或自定义Partitioner,并确保数据无交叠 -
容错能力:启用跳过(
skip-limit="10")和重试(retry-limit="3"),对脏数据或瞬时数据库异常自动绕过或重试,避免整批失败;跳过的记录可通过SkipListener记录到单独日志表供人工核查
元数据与可观测性:别让任务“黑盒运行”
Spring Batch 自带 JobRepository,但默认只存基础状态。生产环境必须:
- 用真实数据库(MySQL/PostgreSQL)初始化 9 张元数据表,禁用
spring.batch.jdbc.initialize-schema=always(仅开发用);特别注意BATCH_JOB_INSTANCE.JOB_KEY字段长度要 ≥100,否则高版本 MySQL 会截断报错 - 关闭自动启动:
spring.batch.job.enabled=false,防止服务一启就触发迁移;改由 XXL-Job、Quartz 或 REST 接口按需触发 - 在 Writer 后添加
StepExecutionListener,统计本次迁移的读/写/跳过数量,写入业务监控表;配合 XXL-Job 的执行日志和告警,实现“哪次失败、错在哪条、影响多少行”一目了然
性能调优与避坑点
实际迁移中几个高频卡点:
- 源库读取慢 → 开启
fetch-size="5000",加覆盖索引(如WHERE status = 'pending' ORDER BY id) - 目标库写入瓶颈 → 关闭外键检查、临时停用非必要索引,迁移后再重建;Doris 场景优先用 Stream Load 或 Broker Load 写入,而非 JDBC
- 中文乱码/时区问题 → 数据库连接 URL 加
useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai - Job 参数重复触发 → 使用
JobParametersBuilder.addLong("time", System.currentTimeMillis())确保每次参数唯一,避免 “JobInstance already exists” 报错
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











