避免在 Spring 批次中处理同一个文件两次

Avoid processing same file twice in Spring Batch

我必须编写一个 Spring 批处理作业,如下所示:

(欢迎对工作结构发表评论,但不是问题)。

在第1步中,我想在加载后将XML文件移动到另一个目录。我希望这个尽可能 "transactional" 写入暂存 table。也就是说,要么写入暂存和文件移动都成功,要么都不成功。

我觉得这是必要的,因为如果 (A) 暂存写入发生但文件没有移动,下一个 运行 将再次拾取文件并再次处理它,并且 (B) 如果文件得到移动但暂存写入没有发生,那么我们将错过该文件的处理。

此接口的要求都是关于稳健性。我知道我可以在最后放置一个步骤执行侦听器来移动所有文件,但我想要一种方法来保证我们永远不会错过处理数据并且永远不会处理同一个文件两次。

部分困难在于我使用的是 MultiResourceItemReader。我读到 ChunkListener.beforeChunk() 作为块事务的一部分发生,所以我尝试制作一个自定义块 CompletionPolicy 以强制块在每次更改资源(文件)名称后完成,但我无法得到它去工作。在任何情况下,我都需要一个 afterChunk() 监听器,它无论如何都不是事务的一部分。

我会就我的具体问题寻求任何指导,或者就如何稳健地处理 Spring 批处理中的文件(我只是刚刚学习)的专家解释。谢谢!

我现在有非常相似的 spring 批处理。

Spring批次符合您的要求。

我建议从这里开始使用 spring 集成。 在 spring 集成中,您可以配置为监视您的文件夹,然后使其触发批处理作业。 official documentation中有很好的例子。

那么你应该使用 spring 批处理的强大概念 - 识别参数。 Spring 批处理作业使用唯一参数运行,如果您将此参数作为标识,则无法使用相同参数生成其他作业(尽管您可以重新启动原始作业)。

/**
 * Add a new String parameter for the given key.
 *
 * @param key - parameter accessor.
 * @param parameter - runtime parameter
 * @param identifying - indicates if the parameter is used as part of identifying a job instance
 * @return a reference to this object.
 */
public JobParametersBuilder addString(String key, String parameter, boolean identifying) {
    parameterMap.put(key, new JobParameter(parameter, identifying));
    return this;
}

所以在这里你需要问问自己,你对批处理作业的唯一标识约束是什么?我建议它是完整的文件路径。但是你需要确保没有人提供具有相同文件名的不同文件。 spring 集成还可以查看文件是否已被应用程序看到并忽略它。请检查 documentation on AcceptOnceFileListFilter

如果你想批量保证 'transactional-like' 逻辑 - 那么不要将它放入监听器,创建一个将移动文件的特定步骤。听众有利于补充逻辑。 这样,如果此步骤因任何原因失败,您仍然可以解决问题并重试作业。

这种过程可以通过 2 个步骤和 1 个侦听器轻松完成:

  1. 一个标准(从XML读取->处理?->写入数据库)步骤;您不关心可重启性,因为 SB 足够聪明,可以避免重复读取数据
  2. 成功执行步骤后附加到步骤 1 以移动文件的侦听器 (example 1, or example 3)
  3. 数据处理的第二步

#3 可作为步骤 1 过程阶段插入