Spring batch Spring批处理事务边界中的整个作业

Spring batch Spring批处理事务边界中的整个作业,spring-batch,spring-batch-tasklet,Spring Batch,Spring Batch Tasklet,我有一个可以使用spring批处理作业的用例,我可以用以下方式设计它 1)第一种方式: 步骤1(面向块的步骤):从文件读取->过滤、验证并将读取的行转换为DTO(数据传输对象),如果有任何错误,将错误存储在DTO本身->检查任何DTO是否有错误,如果没有写入数据库。如果是,则写入错误文件 然而,这种方法的问题是——我需要事务边界中的整个作业。因此,如果在任何块中出现故障,那么我不想写入DB,而是希望回滚所有成功的写入,直到DB中的该点。上面的方法迫使我为所有成功的写操作编写回滚逻辑,如果在任何块

我有一个可以使用spring批处理作业的用例,我可以用以下方式设计它

1)第一种方式:

步骤1(面向块的步骤):从文件读取->过滤、验证并将读取的行转换为DTO(数据传输对象),如果有任何错误,将错误存储在DTO本身->检查任何DTO是否有错误,如果没有写入数据库。如果是,则写入错误文件

然而,这种方法的问题是——我需要事务边界中的整个作业。因此,如果在任何块中出现故障,那么我不想写入DB,而是希望回滚所有成功的写入,直到DB中的该点。上面的方法迫使我为所有成功的写操作编写回滚逻辑,如果在任何块中出现故障

2)第二种方式

步骤1(面向块的步骤):从文件中读取项目->过滤、验证和转换DTO(数据传输对象)中读取的行。这会将错误存储在DTO对象本身中

步骤2(Tasklet):读取从步骤1创建的DTO的整个列表(而不是区块)->检查其中是否有任何DTO填充了错误。如果是,则中止对DB的写入并使作业失败

在第二种方式中,我获得了块处理和扩展的所有好处。同时,我为整个作业创建了事务边界

PS:在两种情况下,在第一步中,如果有任何步骤失败,则不会出现任何步骤失败;错误存储在DTO对象本身中。因此,始终创建DTO对象


问题是-因为我是Spring batch的新手,所以使用second way是否是一种好模式。是否有一种方法可以在步骤之间共享数据,从而使整个DTO列表可用于第二步(在上面的第二种方法中)?

在我看来,尝试在单个事务(即作业级别的事务)中处理整个文件不是一种方法。我将分两步进行:

  • 步骤1:处理输入并将错误写入文件
  • 步骤2:该步骤受步骤1的制约。如果在步骤1中未检测到错误,则将数据保存到数据库
这种方法不需要将数据写入数据库并在出现错误时回滚(如您描述中的选项1所示)。它只在一切正常时写入数据库


此外,这种方法不需要像选项2所建议的那样在内存中保存项目列表,这可能会导致内存使用效率低下,并且如果文件很大,则性能会很差。

您共享了解决方案,但没有共享实际需求。你的实际问题是什么?你能用输入/输出的例子解释一下吗?如果没有Spring批处理,您将如何解决它?FTR,对于整个作业,没有内置的获取事务的方法,请参阅。这是出于设计考虑的,并不是最初的目标,但是没有什么可以阻止您使用它创建
作业
接口的自定义实现(尽管这是一个坏主意,因为它会导致在整个作业期间锁定表的长时间运行事务)。如果您清楚地定义了您的需求,我可以尝试帮助您提供一些关于您的建议和其他备选方案的指导。@MahmoudBenHassine非常感谢您关注这个问题。好吧,让我试着解释一下这个问题。用户上传一个文件,我读取文件并验证、过滤和转换DTO中的每一行。在执行此操作时,无论发生什么验证、过滤和转换错误,我都只将它们存储在该DTO中(DTO中有列表错误)。一旦DTO的最终列表准备就绪,只有当所有DTO都无错误时,我才将它们存储在DB中,即使单个DTO有错误,我也要中止整个操作。目前这是一个同步操作,用户上传并等待结果。我正在使整个过程异步。用户上传一个文件,然后我后端触发一个Spring批处理作业,然后他/她稍后通过电子邮件收到一个结果。现在,我在问题中解释了两个选项。我倾向于第二种方式,但因为我是SpringBatch的新手,所以我想确保它是一种有效的模式。上面的第一种方法需要我编写回滚逻辑,这是我试图避免的。将有来自不同用户的多个上载,后端将触发队列中每次上载的spring批处理作业。步骤2将从何处读取转换项(DTO)?,它们不需要在内存中,以便步骤2可以读取它们并写入数据库吗?另外,我理解您担心的内存效率低下,如果我们将所有项目都保留在内存中,但我将确保只有在服务器上有足够的内存容量时才会触发Spring作业。一旦容量可用,将触发spring批处理作业,以便在队列中进行下一次上载。此外-您是否建议回答中的两个步骤都是面向块的?
它们是否需要在内存中,以便步骤2可以读取它们并写入DB?
不一定。如果它们不适合内存,则可以位于中间持久性存储中,如文件或临时表。将它们保存在内存中的问题是,您无法预先知道需要在内存中保存多少数据(除非您事先进行了计算)。是的,这两个步骤都是面向块的。第二步可能是tasklet,如果您选择该路径,它将临时表复制到非临时表中。非常感谢您的时间和回复。我很感激!