bigywater.tech
Spring · 145

Spring Batch:skip、retry 与重启

Spring Batch 遇到坏数据怎么办?skip 和 retry 怎么用?writer 失败为什么会被调用那么多次?skipLimit 超了会怎样?失败后重启是从断点继续还是从头来?这篇在 Spring Batch 6.0.5 和 MySQL 上逐项实测。

13 次
writer 在第 15 条失败并允许跳过时被调用的次数,正常只需要 3 次
重复 200 行
不可重启的 ListItemReader 在失败后重启,表里 1200 行
n+1
retryLimit(n) 的总尝试次数

默认失败

实测 · 本机执行输出
  Job FAILED/Step FAILED,read=10 write=0 skip=0(读 0/处理 0/写 0) commit=0 rollback=1,失败原因 FatalStepExecutionException,表里 0 行

任何异常让步骤失败,当前 chunk 回滚。

skip

实测 · 本机执行输出
  Job COMPLETED/Step COMPLETED,read=30 write=29 skip=1(读 0/处理 1/写 0) commit=3 rollback=0,处理器被调用 30 次,表里 29 行,缺的是 [7]

processor 异常就地跳过。

超出 skipLimit

实测 · 本机执行输出
  Job FAILED/Step FAILED,read=10 write=0 skip=2(读 0/处理 2/写 0) commit=0 rollback=1,失败原因 FatalStepExecutionException,表里 0 行

当前 chunk 整块回滚。

writer 失败

实测 · 本机执行输出
  Job COMPLETED/Step COMPLETED,read=30 write=29 skip=1(读 0/处理 0/写 1) commit=3 rollback=2,writer 被调用 13 次,表里 29 行,缺的是 [15]

回滚后逐条重写,调用次数暴增。

retry

实测 · 本机执行输出
  Job COMPLETED/Step COMPLETED,read=10 write=10 skip=0(读 0/处理 0/写 0) commit=1 rollback=0,处理器被调用 12 次(10 条 + 额外的 2 次重试),表里 10 行
  第 5 条前 3 次都抛 Transient,retryLimit(2):Job FAILED/Step FAILED,read=10 write=0 skip=0(读 0/处理 0/写 0) commit=0 rollback=1,失败原因 FatalStepExecutionException,处理器被调用 7 次,表里 0 行
  第 5 条前 3 次都抛 Transient,retryLimit(3):Job COMPLETED/Step COMPLETED,read=10 write=10 skip=0(读 0/处理 0/写 0) commit=1 rollback=0,处理器被调用 13 次,表里 10 行

retryLimit(n) = 最多重试 n 次。

重启

实测 · 本机执行输出
  [ListItemReader(不可重启的读取器)] 第一次:Job FAILED/Step FAILED,read=300 write=200 skip=0(读 0/处理 0/写 0) commit=2 rollback=1,失败原因 FatalStepExecutionException,表里 200 行
    第二次(同参数重启):Job COMPLETED/Step COMPLETED,read=1000 write=1000 skip=0(读 0/处理 0/写 0) commit=10 rollback=0,表里 1200 行,去重后 1000 行;同一个 JobInstance 下的执行数 2,两次的 JobInstance 是否相同 true
  [JdbcCursorItemReader(有名字,会保存读取位置)] 第一次:Job FAILED/Step FAILED,read=300 write=200 skip=0(读 0/处理 0/写 0) commit=2 rollback=1,失败原因 FatalStepExecutionException,表里 200 行
    第二次(同参数重启):Job COMPLETED/Step COMPLETED,read=800 write=800 skip=0(读 0/处理 0/写 0) commit=8 rollback=0,表里 1000 行,去重后 1000 行;同一个 JobInstance 下的执行数 2,两次的 JobInstance 是否相同 true

读取器可重启才能从断点继续。

分步演示

Batch 容错
本步的对象

    本文用到的工具与边界

    • 本机 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);步骤用新的 chunk(n) 构建器加 faultTolerant();故障由代码里的计数器和开关人为制造;读取器对比用 ListItemReader 与带名字的 JdbcCursorItemReader
    • 没有验证:SkipListener / RetryListener 记录被跳过的数据;skip 与 retry 的组合顺序;backoff(重试之间的退避)配置;读取阶段异常的跳过(readSkipCount);FlatFileItemReader 的重启;旧版 SimpleStepBuilder 的 faultTolerant 行为是否相同;多线程步骤下的 skip;RunIdIncrementer 与 startNextInstance;abandon / 卡在 STARTED 状态的执行如何处理
    京ICP备2026067502号-1京公网安备11010502063487号