Spring Batch 近期同时推出了 6.0.4 和 5.2.6 两个维护版本。两个版本在同一天发布,说明团队仍在并行维护两条主线——6.x 面向 Spring Framework 6 / Java 17+ 的新项目,5.x 继续为尚未完成 Java 版本升级的存量系统提供安全与稳定性保障。
如果你正在评估 Spring Batch 或准备迁移版本,这次双线发布是一个很好的切入点:搞清楚两条线的差异,才能做出正确的依赖选择。
两条维护线的定位差异
Spring Batch 6.x 系列随 Spring Boot 3.x 一起演进,底层依赖 Spring Framework 6,最低要求 Java 17。它引入了若干结构性变更——比如对 ItemStream 生命周期管理的调整、对 JobRepository 接口的精简、以及与 Spring Framework 6 的观测体系(Observation API)的集成。
5.x 系列则停留在 Spring Framework 5 的生态里,最低支持 Java 8(5.2.x 实际建议 Java 11+),适合仍在运行 Spring Boot 2.x 的项目。5.2.6 这类补丁版本主要修复已知缺陷和兼容性问题,不会引入新特性。
简单判断规则:
| 条件 | 推荐版本 |
|---|---|
| 新项目,Spring Boot 3.x,Java 17+ | 6.0.4 |
| 存量项目,Spring Boot 2.x,Java 8/11 | 5.2.6 |
| 正在从 5.x 迁移到 6.x | 先升到 5.2.6 确保稳定,再跨版本迁移 |
6.0.4 补丁关注什么
作为 6.0 线的第四次补丁,6.0.4 主要修复的是 6.0.0 引入新架构后暴露的边界问题。常见的补丁方向包括:
- JobRepository 事务边界修正:6.0 重构了
JobRepository的实现,早期版本在某些并发场景下可能出现死锁或事务超时,补丁版本逐步收紧了锁的范围。 - StepExecution 序列化兼容:6.0 调整了
StepExecution的字段结构,补丁修复了与旧版本数据库记录的兼容读取问题。 - Observation API 集成完善:6.0 开始用 Micrometer Observation 替代旧版
BatchMetrics,补丁版本补充了缺失的指标标签和上下文传递。
如果你的项目已经在用 6.0.0–6.0.3,升级到 6.0.4 是低风险的——补丁版本不改变公共 API 签名。
5.2.6 补丁关注什么
5.2.6 是 5.x 线的第六次补丁,修复范围更偏向存量系统的实际痛点:
- 数据库方言兼容:某些数据库(如 DB2、MariaDB 特定版本)的
JobRepositorySQL 脚本存在语法问题,补丁做了针对性修正。 - Chunk-oriented 处理边界条件:在
faultTolerant步骤中,skip与retry的叠加逻辑在特定异常组合下可能跳过不该跳过的记录,补丁收紧了判定逻辑。 - FlatFileItemReader/Writer 编码处理:部分非 UTF-8 编码的文件在读取时出现截断,补丁修正了
BufferedReader的编码初始化顺序。
实践:用 Spring Batch 6.0.4 写一个最小可运行 Job
下面给出一个完整的、可直接复制运行的最小 Spring Batch 项目示例。假设你使用 Spring Boot 3.2+ 和 Java 17。
项目依赖(pom.xml 关键片段)
<properties>
<java.version>17</java.version>
<spring-batch.version>6.0.4</spring-batch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<!-- 内存 JobRepository,不需要真实数据库;生产环境请换为 JDBC -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
生产环境务必把 HSQLDB 换成 MySQL / PostgreSQL 等持久化数据库,并配置
spring.batch.jdbc.initialize-schema=always或使用 Flyway 管理 schema。
Job 配置类
package com.example.batch;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class HelloBatchConfig {
// --- Reader:逐条返回数据,返回 null 表示结束 ---
@Bean
ItemReader<String> reader() {
String[] data = {"alice", "bob", "carol", "dave"};
// 用数组索引模拟有界读取
return new ItemReader<>() {
private int idx = 0;
@Override
public String read() {
return idx < data.length ? data[idx++] : null;
}
};
}
// --- Processor:把名字转成大写 ---
@Bean
ItemProcessor<String, String> processor() {
return name -> name.toUpperCase();
}
// --- Writer:打印到控制台 ---
@Bean
ItemWriter<String> writer() {
return chunk -> chunk.forEach(System.out::println);
}
// --- Step:chunk 大小 2,每次处理两条记录 ---
@Bean
Step helloStep(JobRepository jobRepository,
PlatformTransactionManager txManager,
ItemReader<String> reader,
ItemProcessor<String, String> processor,
ItemWriter<String> writer) {
return new StepBuilder("helloStep", jobRepository)
.<String, String>chunk(2, txManager)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
// --- Job ---
@Bean
Job helloJob(JobRepository jobRepository, Step helloStep) {
return new JobBuilder("helloJob", jobRepository)
.start(helloStep)
.build();
}
}
启动类
package com.example.batch;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloBatchApp {
public static void main(String[] args) {
SpringApplication.run(HelloBatchApp.class, args);
}
}
运行与预期输出
# 打包并运行
mvn clean package -DskipTests
java -jar target/hello-batch-app-0.0.1-SNAPSHOT.jar
控制台应输出:
ALICE
BOB
CAROL
DAVE
每两条记录作为一个 chunk 提交一次事务——你可以把 chunk 大小改成 1 或 4 来观察提交频率的变化。
从 5.x 迁移到 6.x 的实操要点
如果你决定从 5.2.6 升到 6.0.4,以下是最容易踩坑的几处:
- Java 版本先到位:6.x 要求 Java 17,这是硬性前提,没有妥协空间。
- JobRepository API 变化:6.0 把部分方法签名从
JobRepository接口移除或重命名,自定义实现需要对照迁移指南逐条检查。 - Schema 变更:6.0 的
BATCH_JOB_INSTANCE等表结构与 5.x 有字段差异。迁移时要么清空旧表重新初始化,要么执行官方提供的增量 DDL 脚本。 - Metrics 替换:如果你在 5.x 中使用了
BatchMetrics,6.x 改为 Micrometer Observation API,需要重新注册指标并调整标签体系。 - 先升到 5.2.6 再跨版本:确保 5.x 线上所有已知 bug 已修复,再开始 6.x 迁移,可以减少排查时的干扰变量。
升级检查清单
在决定版本和执行升级前,逐项确认:
- [ ] 当前项目的 Java 最低版本是否满足目标线的要求?
- [ ] Spring Boot 版本是否与 Spring Batch 大版本对齐(Boot 3 → Batch 6,Boot 2 → Batch 5)?
- [ ] JobRepository 的数据库 schema 是否需要增量迁移脚本?
- [ ] 自定义的
ItemStream/JobRepository实现是否需要适配新接口? - [ ] 监控指标是否从旧体系迁移到 Micrometer Observation?
- [ ] 是否有第三方 Spring Batch 扩展(如 Spring Batch Integration)需要同步升级?
两条线并行维护是好事——它给了存量项目喘息空间,也给新项目提供了更现代的基础设施。选对版本线、按清单逐步迁移,比盲目追新更稳妥。