Spring batch 如何在Spring批处理中实现跳过?
我想知道如何在我的Spring batch 如何在Spring批处理中实现跳过?,spring-batch,skip,fallback,chunks,Spring Batch,Skip,Fallback,Chunks,我想知道如何在我的ItemWriter中确定Spring批处理当前处于块处理模式还是回退单项处理模式。首先,我没有找到这个回退机制是如何实现的信息 即使我还没有找到解决我实际问题的方法,我也愿意与您分享我对回退机制的知识 如果我遗漏了任何内容,请随时添加带有附加信息的答案;-) 可以在和中找到跳过机制的实现 假设您已配置,但没有。并且当前块中有一个失败项导致异常 现在,首先要写出整段文字。在处理器的write()方法中,可以看到调用了RetryTemplate。它还获取对RetryCallbac
ItemWriter
中确定Spring批处理当前处于块处理模式还是回退单项处理模式。首先,我没有找到这个回退机制是如何实现的信息
即使我还没有找到解决我实际问题的方法,我也愿意与您分享我对回退机制的知识
如果我遗漏了任何内容,请随时添加带有附加信息的答案;-) 可以在和中找到跳过机制的实现 假设您已配置,但没有。并且当前块中有一个失败项导致异常 现在,首先要写出整段文字。在处理器的
write()
方法中,可以看到调用了RetryTemplate
。它还获取对RetryCallback
和RecoveryCallback
的两个引用
切换到RetryTemplate
。找到以下方法:
protected <T> T doExecute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState state)
这就是单一项目处理模式现在开始的地方强>
RecoveryCallback(在处理器的write()
方法中定义!)将锁定输入块(inputs.setBusy(true)
)并运行其scan()
方法。在这里,您可以看到,从块中提取了单个项:
List items=Collections.singletonList(outputIterator.next())代码>
如果ItemWriter
可以正确处理此单个项目,则区块将完成,ChunkOrientedTasklet
将运行另一个区块(用于下一个单个项目)。这将导致定期调用RetryCallback
,但由于块已被RecoveryTemplate
锁定,因此将立即调用scan()
方法:
if (!inputs.isBusy()) {
// ...
}
else {
scan(contribution, inputs, outputs, chunkMonitor);
}
因此,将处理另一个项目,并重复此操作,直到逐个项目处理原始块:
if (outputs.isEmpty()) {
inputs.setBusy(false);
就这样。我希望这对你有帮助。我更希望你能通过搜索引擎轻松找到这些信息,不要浪费太多时间,自己去发现这些信息 解决我的原始问题的一种可能方法(ItemWriter想知道,它是在区块模式还是单项目模式下)可以是以下备选方案之一:
- 只有当传递的块的大小为1时,才需要进行进一步的检查
- 当传递的区块是
java.util.Collections.SingletonList
时,我们可以非常确定,因为FaultTolerantChunkProcessor
执行以下操作:
List items=Collections.singletonList(outputIterator.next())强>
不幸的是,这个类是私有的,因此我们不能用instanceOf
检查它
- 相反,如果区块是
ArrayList
,我们也可以非常确定,因为Spring批处理的chunk
类使用它:
私有列表项=新的ArrayList()强>
- 一个模糊的左边是从执行上下文读取的缓冲项。但我希望这些人也是ArrayList
无论如何,我还是觉得这个方法太模糊了。我希望框架提供这些信息
另一种方法是在框架执行中钩住我的ItemWriter
。也许ItemWriteListener.onWriteError()
是合适的
更新:如果您处于单项目模式,并且在ItemWriter
中引发异常,则不会调用onWriteError()
方法。我想这是一个bug,我把它归档了:
所以这个替代方案退出了
这里有一个片段可以在编写器中直接执行相同的操作,而不需要任何框架
private int writeErrorCount = 0;
@Override
public void write(final List<? extends Long> items) throws Exception {
try {
writeWhatever(items);
} catch (final Exception e) {
if (this.writeErrorCount == 0) {
this.writeErrorCount = items.size();
} else {
this.writeErrorCount--;
}
throw e;
}
this.writeErrorCount--;
}
public boolean isWriterInSingleItemMode() {
return writeErrorCount != 0;
}
private int writeErrorCount=0;
@凌驾
public void write(最终列表你能解释一下现实世界中的问题吗?这个问题让你想到“编写者如何知道当前的处理模式”?当然:-)我正在存储一个业务日志(在我的技术日志旁边)。在此日志中,每个项目的消息只应出现一次。如果在处理过程中出现异常,我还将在业务日志中为此项写入错误日志。如果某个项目已被处理但已回滚,我对其错误日志不感兴趣。我只想在处理单个项目时记录这些错误。否则,如果我处于块模式,我可能会记录好的项的错误,只是因为它们在坏块中。我们不能在单例列表上调用instanceof,但这是有效的:Class singletonListClazz=Class.forName(“java.util.Collections$SingletonList”);布尔重试=假;如果(items.getClass().equals(singletonListClazz)){retrying=true;}
@slh777谢谢您的建议。这确实有效。但是,我对这种方法不满意,因为我们严重依赖于框架的实现细节(即,在SingleItemMode下返回SingletonList)。我更希望看到框架对这一点进行封装:-(
private int writeErrorCount = 0;
@Override
public void write(final List<? extends Long> items) throws Exception {
try {
writeWhatever(items);
} catch (final Exception e) {
if (this.writeErrorCount == 0) {
this.writeErrorCount = items.size();
} else {
this.writeErrorCount--;
}
throw e;
}
this.writeErrorCount--;
}
public boolean isWriterInSingleItemMode() {
return writeErrorCount != 0;
}