问题描述
我有一个可以使用 spring 批处理作业的用例,我可以通过以下方式设计它。
1) 第一种方式:
Step1(面向Chunk的步骤):从文件中读取——>过滤、验证并将读取的行转换为DTO(数据传输对象),如果有任何错误,将错误存储在DTO本身中—> 检查是否有任何 DTO 有错误,如果没有写入数据库。如果是,则写入错误文件。
但是,这种方式的问题是 - 我需要事务边界中的整个 JOB。因此,如果任何块中出现故障,那么我不想写入 DB 并希望将所有成功写入回滚到 DB 中的那个点。如果任何块中出现故障,上述方式迫使我为所有成功写入编写回滚逻辑。
2) 第二种方式
步骤 1(面向块的步骤):从文件中读取项目 —> 在 DTO(数据传输对象)中过滤、验证和转换读取的行。这确实将错误存储在 DTO 对象本身中。
第 2 步(tasklet):读取从第 1 步创建的 DTO 的整个列表(而不是块)—> 检查是否有任何 DTO 中填充了错误。如果是,则中止写入 DB 并使 JOB 失败。
第二种方式,我获得了块处理和缩放的所有好处。同时我为整个工作创建了事务边界。
PS:在他们的第一步中,两种方式都不会有任何一步失败,如果有失败;错误存储在 DTO 对象本身中。因此,始终创建 DTO 对象。
问题是 - 由于我是 Spring 批处理的新手,采用第二种方式是否是一个好模式。有没有一种方法可以在步骤之间共享数据,以便整个 DTO 列表可用于第二步(上面的第二种方式)?
解决方法
在我看来,尝试在单个事务(即作业级别的事务)中处理整个文件不是可行的方法。我将分两步进行:
- 第 1 步:处理输入并将错误写入文件
- 第 2 步:这一步受第 1 步的制约。如果在步骤 1 中没有检测到错误,则将数据保存到数据库中。
这种方法不需要将数据写入数据库并在出现错误时将其回滚(如您描述中的选项 1 所建议的那样)。仅在一切正常时才写入数据库。
此外,这种方法不需要像选项 2 建议的那样在内存中保存项目列表,这在内存使用方面可能效率低下,并且如果文件很大,则性能会很差。