Appearance
⚙️ Spring Batch 重试逻辑配置指南
核心要义:在批处理中,非确定性异常可通过重试解决,而确定性异常重试无效!
🧠 为什么需要重试机制?
异常类型对比
异常类型 | 特点 | 是否适合重试 | 典型场景 |
---|---|---|---|
确定性异常 | 相同操作必然发生 | ❌ 不适合 | FlatFileParseException (文件解析错误) |
非确定性异常 | 由临时状态引起 | ✅ 适合 | DeadlockLoserDataAccessException (数据库死锁) |
🛠️ Kotlin 配置实战
基础重试配置
kotlin
@Configuration
@EnableBatchProcessing
class BatchConfig {
@Bean
fun step1(jobRepository: JobRepository,
transactionManager: PlatformTransactionManager): Step {
return StepBuilder("step1", jobRepository)
.chunk<String, String>(10, transactionManager)
.reader(myItemReader())
.processor(myItemProcessor())
.writer(myItemWriter())
.faultTolerant() // 启用容错机制
.retryLimit(3) // 最大重试次数
.retry(DeadlockLoserDataAccessException::class.java) // 指定重试异常
.build()
}
// 其他bean定义...
}
多异常类型重试
kotlin
// 在step配置中添加:
.retryLimit(5)
.retry(DeadlockLoserDataAccessException::class)
.retry(OptimisticLockingFailureException::class)
.retry(ConcurrencyFailureException::class)
WARNING
危险配置警告
避免对确定性异常配置重试!以下配置会导致无效重试循环:
kotlin
.retry(FlatFileParseException::class)
⚡ 高级配置技巧
指数退避策略
kotlin
// 添加重试策略配置
val retryPolicy = SimpleRetryPolicy().apply {
maxAttempts = 5
}
val backOffPolicy = ExponentialBackOffPolicy().apply {
initialInterval = 1000 // 初始间隔1秒
multiplier = 2.0 // 指数倍数
maxInterval = 10000 // 最大间隔10秒
}
return StepBuilder("advancedStep", jobRepository)
.chunk<String, String>(10, transactionManager)
.faultTolerant()
.retryPolicy(retryPolicy)
.backOffPolicy(backOffPolicy) // 设置退避策略
.build()
自定义重试决策器
kotlin
class CustomRetryDecider : RetryPolicy {
override fun canRetry(context: RetryContext): Boolean {
val ex = context.lastThrowable
// 仅重试特定错误码的异常
return (ex is MyBusinessException && ex.errorCode == "RETRYABLE")
}
}
// 在Step中使用:
.retryPolicy(CustomRetryDecider())
🚨 关键注意事项
性能警告
过度重试会导致批处理作业严重延迟!建议:
- 设置合理的重试上限(通常3-5次)
- 结合监控告警机制
- 避免在写入操作中重试整个chunk
最佳实践
- 隔离重试逻辑:为不同操作配置不同重试策略
kotlin
// 仅为写入操作配置重试
writer(myItemWriter())
.faultTolerant()
.retryLimit(3)
.retry(DataAccessException::class)
- 结合跳过机制:重试失败后跳过当前记录而非终止作业
kotlin
.retryLimit(3)
.skipLimit(10) // 允许跳过10条记录
.skip(DeadlockLoserDataAccessException::class)
🔍 深度解析:重试工作原理
IMPORTANT
核心机制
Spring Batch的重试是基于单条记录的,而非整个chunk。每次重试都会:
- 回滚当前事务
- 重新处理相同记录
- 独立计数每条记录的重试次数
💎 总结
配置要素 | 推荐方案 | 工具方法 |
---|---|---|
重试异常类型 | 非确定性异常 | .retry(异常类) |
重试次数 | 3-5次 | .retryLimit(次数) |
重试间隔 | 指数退避策略 | .backOffPolicy() |
失败处理 | 结合跳过机制 | .skipLimit().skip() |
监控 | 记录重试日志 + 告警 | RetryListener 接口实现 |
kotlin
@Bean
fun robustStep(jobRepository: JobRepository,
txManager: PlatformTransactionManager): Step {
return StepBuilder("secureStep", jobRepository)
.chunk<Data, Result>(5, txManager)
.reader(dbItemReader())
.processor(validationProcessor())
.writer(jdbcWriter())
.faultTolerant()
.retryLimit(3)
.retry(DeadlockLoserDataAccessException::class)
.retry(TransientDataAccessException::class)
.skipLimit(100)
.skip(DataIntegrityViolationException::class)
.listener(retryMonitoringListener()) // 监控监听器
.build()
}
⚡ 行动建议:
立即检查你的批处理作业,为这些异常添加重试支持:
DeadlockLoserDataAccessException
OptimisticLockingFailureException
QueryTimeoutException
SocketException
(网络操作时)