【发布时间】:2021-07-18 16:28:55
【问题描述】:
有没有办法改变 ItemProcessor 的跳过行为,使其表现得像 ItemWriter?在 ItemProcessor 中抛出可跳过的异常会导致重新处理所有已接受的项目,从而导致其复杂性呈二次方的行为。有没有办法改变行为以对所有项目进行回滚并逐个处理元素,就像 ItemWriter 一样?
工作定义:
@Bean
public Job job() {
return jobBuilderFactory.get("job").start(step(null)).build();
}
@Bean
public Step step(ReaderProcessorWriter readerProcessorWriter) {
return stepBuilderFactory.get("step")
.<Integer, Integer>chunk(20).faultTolerant()
.skip(RuntimeException.class).skipLimit(10)
.reader(readerProcessorWriter)
.processor(readerProcessorWriter)
.writer(readerProcessorWriter)
.build();
}
读取器、处理器和写入器:
@Component
public static class ReaderProcessorWriter extends ListItemReader<Integer> implements ItemProcessor<Integer, Integer>, ItemWriter<Integer> {
private int run;
public ReaderProcessorWriter() {
super(List.of(0, 1, 2, 3, 4, 5, 6, 7,8 ,9));
}
@Override
public Integer process(Integer integer) {
// Probably some long computation involving lots of DB Reading, lasting minutes at worst
if (integer >= 5) {
System.out.println("FAIL: " + integer);
throw new RuntimeException("Hue hue");
}
System.out.println("OK: " + integer);
return integer;
}
@Override
public void write(List<? extends Integer> list) {
if (run++ == 0) {
throw new RuntimeException("Writer");
}
System.out.println(list);
}
}
输出:
OK: 0
OK: 1
OK: 2
OK: 3
OK: 4
FAIL: 5
OK: 0
OK: 1
OK: 2
OK: 3
OK: 4
FAIL: 6
OK: 0
OK: 1
OK: 2
OK: 3
OK: 4
FAIL: 7
OK: 0
OK: 1
OK: 2
OK: 3
OK: 4
FAIL: 8
OK: 0
OK: 1
OK: 2
OK: 3
OK: 4
FAIL: 9
OK: 0
OK: 1
OK: 2
OK: 3
OK: 4
OK: 0
[0]
OK: 1
[1]
OK: 2
[2]
OK: 3
[3]
OK: 4
[4]
在示例中,项目 0-4 在成功写入之前被处理了 6 次(假设 Writer 不会抛出)。
- 5 次,因为处理器上的回滚
- 1 表示处理成功
如果 ItemProcessor 使用与 ItemWriter 相同的跳过策略,那么它们只会被处理 2 次:
- 1 次处理失败
- 1 次单独交易
【问题讨论】:
-
也许使用 RetryTemplate?
-
也许使用 RetryTemplate?见:baeldung.com/spring-retry
-
重试模板仅适用于瞬态异常,例如网络故障、并发修改或乐观锁定。如果异常是由格式错误的数据引起的,那么 RetryTemplate 会导致 Step Failure 而不是 Skipping element。
-
我的意思是用它来管理一些外部状态对象以防出现异常并将该对象用作水印来恢复处理?我在互联网上找不到其他任何东西,也许是因为批处理并不意味着在失败的情况下恢复,我认为您将不得不实施一种解决方法
-
是的。这就是 Skip 机制的原因。有一个简单的解决方案 - 只需将所有业务逻辑移至 ItemWriter,但这不是最干净的方法。使用内部对象的方法失败了,因为事务已回滚并且从未发生写入并且它与可重新启动性混淆。
标签: java spring spring-batch