bigywater.tech
Spring · 144

Spring Batch:Job、Step 与 chunk

Spring Batch 的 chunk 到底是什么?设多大合适?Boot 重启为什么会因为 Batch 启动失败?处理器返回 null 会怎样?中途失败已经写入的数据还在吗?为什么同样的参数不能再跑一次?这篇在 Spring Batch 6.0.5 和真实 MySQL 上逐项实测。

2247 ms
chunk=1 处理并写入 5000 条的耗时,chunk=100 时是 169 ms
启动失败
无参数的 Job,第二次启动同一个库,JobInstanceAlreadyCompleteException
200 行
写第 250 条抛异常、chunk=100 时表里保留的行数,第三个 chunk 整块回滚

自动运行

实测 · 本机执行输出
  第一次启动(spring.batch.job.enabled 保持默认):  Tasklet 执行了 |   应用结束时 BATCH_JOB_EXECUTION 共 1 行
  第二次启动(同一个库、Job 没有 JobParameters):退出码 1,没有任何输出;异常:Exception in thread "main" java.lang.IllegalStateException: Failed to execute ApplicationRunner / Caused by: org.springframework.batch.core.launch.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for identifying parameters={}.  If you want to run this job again, c
  spring.batch.job.enabled=false:  应用结束时 BATCH_JOB_EXECUTION 共 1 行

spring.batch.job.enabled 默认 true,重启会重跑 Job。

chunk 大小

实测 · 本机执行输出
  chunk=1:Job COMPLETED/Step COMPLETED,read=5000 filter=0 write=5000 commit=5000 rollback=0,writer 被调用 5000 次,表里 5000 行,耗时 2247 ms
  chunk=10:Job COMPLETED/Step COMPLETED,read=5000 filter=0 write=5000 commit=500 rollback=0,writer 被调用 500 次,表里 5000 行,耗时 363 ms
  chunk=100:Job COMPLETED/Step COMPLETED,read=5000 filter=0 write=5000 commit=50 rollback=0,writer 被调用 50 次,表里 5000 行,耗时 169 ms
  chunk=1000:Job COMPLETED/Step COMPLETED,read=5000 filter=0 write=5000 commit=5 rollback=0,writer 被调用 5 次,表里 5000 行,耗时 147 ms

提交次数 = 条数 ÷ chunk,耗时随 chunk 增大先降后平。

过滤

实测 · 本机执行输出
  Job COMPLETED/Step COMPLETED,read=1000 filter=500 write=500 commit=10 rollback=0,writer 被调用 10 次,表里 500 行

processor 返回 null 即过滤。

失败回滚

实测 · 本机执行输出
  Job FAILED/Step FAILED,read=300 filter=0 write=200 commit=2 rollback=1,ExitStatus=FAILED,表里 200 行(两个完整的 chunk 已经提交,第三个整块回滚)

当前 chunk 整块回滚,前面的保留。

JobInstance

实测 · 本机执行输出
  第一次:COMPLETED
  第二次抛出 JobInstanceAlreadyCompleteException:A job instance already exists and is complete for identifying parameters={JobParameter{name='date', value=2026-10-22, type=class java.lang.String, identifying=true}}.  If you want to run this job again, change the parameters.
  换一个参数 date=2026-10-23:COMPLETED
  BATCH_JOB_INSTANCE 里 daily 的实例数 2;BATCH_JOB_EXECUTION 里 daily 的执行数 2
  元数据表:[BATCH_JOB_EXECUTION, BATCH_JOB_EXECUTION_CONTEXT, BATCH_JOB_EXECUTION_PARAMS, BATCH_JOB_EXECUTION_SEQ, BATCH_JOB_INSTANCE, BATCH_JOB_INSTANCE_SEQ, BATCH_STEP_EXECUTION, BATCH_STEP_EXECUTION_CONTEXT, BATCH_STEP_EXECUTION_SEQ]
  应用结束时 BATCH_JOB_EXECUTION 共 8 行

Job 名 + 标识参数,完成后不能重跑。

分步演示

Spring Batch chunk
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。MySQL 是自己起的独立实例;用 spring-boot-starter-batch-jdbc(元数据存在 MySQL 里),spring.batch.jdbc.initialize-schema=always;步骤用新的 chunk(n) 构建器(ChunkOrientedStep),writer 是自己写的 JdbcTemplate.batchUpdate;耗时是单次测量,5000 条的小数据
    • 没有验证:不带 JDBC 的 spring-boot-starter-batch(内存 / 无状态 JobRepository)的行为;旧的 chunk(n, transactionManager)(SimpleStepBuilder)与新构建器的差别;多线程 Step(taskExecutor)、分区、并行 Flow;读取器的游标与分页(JdbcCursorItemReader / JdbcPagingItemReader);Job 的 RunIdIncrementer;监听器;skip / retry / 重启(见第 145 篇)
    京ICP备2026067502号-1京公网安备11010502063487号