存储来自 Spring 个批处理分区工作步骤的作业级数据的最佳方法是什么?

What is the best way to store job level data from Spring batch partition worker steps?

我有一个 spring 批处理作业。它处理大量项目。对于每个项目,它调用一个外部服务(假设一个存储过程或一个 REST 服务。这会做一些业务计算并更新数据库。这些结果用于生成一些分析报告。)。每个项目都是独立的,因此我将外部调用划分为同一个 JVM 中的 10 个分区。例如,如果有 50 个项目要处理,则每个分区将有 50/10 = 5 个项目要处理。 此外部服务可以生成 SUCCESSFAILURE return 代码。所有业务逻辑都封装在这个外部服务中,因此工作步骤是一个 tasklet,它只调用外部服务并接收 SUCCESS/FAILURE 标志。我想为每个项目存储所有 SUCCESS/FAILURE 标志,并在工作结束时获取它们。这些是我能想到的方法:

  1. 每个工作步骤都可以将项目及其 SUCCESS/FAILURE 存储在一个集合中,并将其存储在作业执行上下文中。 Spring 批处理保留执行上下文,我可以在作业结束时检索它。这是最天真的方式,当所有 10 个工作步骤都尝试访问和修改同一个集合时会导致线程争用。
  2. 第一种方法中的并发异常可以通过使用像 CopyOnWriteArrayList 这样的并发集合来避免。但这代价太大,当每个工作步骤都在等待访问列表时,分区的整个目的就被打败了。
  3. 我可以将项目 ID 和 success/failure 写入外部 table 或消息队列。这将避免上述 2 种方法中的问题,但我们将使用 spring bath 框架来实现这一点。我的意思是我们没有使用 spring 批处理作业执行上下文,而是使用外部数据库或消息队列。

有没有更好的方法来做到这一点?

您仍然没有回答有关您将使用哪个项目编写器的问题,因此我将尝试回答您的问题并向您展示为什么这个细节对于选择正确的问题解决方案至关重要。

这是您的要求:

I have a spring batch job. It processes a large number of items.
For each item, it calls an external service (assume a stored procedure
or a REST service. This does some business calculations and updates a database.

在您的描述中,您是在谈论将项目 ID 及其状态存储在作业执行上下文中。虽然这是可能的,但我要说的是,如果您打算将项目写入 table 无论如何您有一个带有状态标志的列,您不需要使用作业执行上下文全部。因此我的问题是:

are you going to write the items themselves to a persistent store?
The item writer is required in a chunk-oriented step and the solution
depends on how you are going to write items (also, is the success/failure
status just a flag? or a different object with more information?, etc).
Where those items are going to be written? A table, a file, to the standard
output with System.out ?

所以我假设您要将项目写入 table,因为您说过 This does some business calculations and updates a database

您可以使用项目处理器来执行业务逻辑并标记项目及其状态(即您的域对象具有处理器根据需要设置的标志 status)。项目编写者然后用它们的状态更新数据库中的项目。这种方法通过设计解决了上面列出的所有问题,因为它不需要作业执行上下文,并且是多线程或分区步骤的一个很好的选择(因为项目是独立的)。