Spring 批处理事务管理是如何工作的?

How does Spring Batch transaction management work?

我正在尝试了解 Spring Batch 如何进行事务管理。这不是技术问题,而是概念性问题:Spring Batch 使用什么方法以及该方法的后果是什么?

让我试着澄清一下这个问题。例如,查看 TaskletStep,我发现通常步骤执行看起来像这样:

  1. 几个 JobRepository 事务 来准备步骤元数据
  2. 每个要处理的块业务事务
  3. 更多 JobRepository 事务 使用块处理的结果更新步骤元数据

这似乎有道理。但是 2 和 3 之间的失败怎么办?这意味着业务事务已提交,但 Spring Batch 无法在其内部元数据中记录该事实。因此,重新启动将再次重新处理相同的项目,即使它们已经提交。对吗?

我正在寻找对这些细节的解释以及在 Spring 批处理中做出的设计决策的后果。这在某处记录了吗? Spring 批处理参考指南对此的详细信息很少。它只是从应用程序开发人员的角度来解释事情。

Spring批处理中有两种基本类型的步骤,Tasklet 步骤和基于块的步骤。每个都有自己的交易细节。让我们看看每个:

基于任务的步骤
当开发人员实现他们自己的 tasklet 时,事务性非常简单。对 Tasklet#execute 方法的每次调用都在一个事务中执行。您是正确的,因为在执行步骤的逻辑之前和之后都有更新。它们在技术上没有包含在事务中,因为回滚不是我们想要支持的作业存储库更新。

基于块的步骤
当开发人员使用基于块的步骤时,由于 skip/retry 的附加功能,涉及的复杂性会更高一些。但是,从简单的层面来说,每个chunk都是在一个事务中处理的。由于前面提到的相同原因,您在基于块的步骤之前和之后仍然有相同的更新,这些更新是非事务性的。

"What if"场景
在您的问题中,您询问如果业务逻辑完成但作业存储库更新由于某种原因失败会发生什么。是否会在重新启动时重新处理先前更新的项目。与大多数事情一样,这取决于。如果您使用像 FlatFileItemReader 这样的有状态 readers/writers,随着业务事务的每次提交,作业存储库将更新为已处理内容的当前状态(在同一事务中)。因此,在那种情况下,作业的重新启动将从它停止的地方开始……在这种情况下,在最后,并且不处理任何额外的记录。

如果您没有使用有状态 readers/writers 或关闭了保存状态,那么请买家当心,您最终可能会遇到您描述的情况。框架中的默认行为是保存状态,以便保留可重启性。