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;
}