我们如何在Spring Batch的作业的不同步骤之间共享数据?

kar*_*ana 56 spring-batch

深入研究Spring Batch,我想知道如何在作业的不同步骤之间共享数据?

我们可以使用JobRepository吗?如果是的话,我们怎么做?

有没有其他方法可以做到/达到同样的目的?

Win*_*ked 36

作业存储库间接用于在步骤之间传递数据(Jean-Philippe是正确的,最好的方法是将数据放入StepExecutionContext,然后使用详细命名ExecutionContextPromotionListener来将步骤执行上下文键提升为JobExecutionContext.

值得注意的是,有一个监听器可以将JobParameter密钥提升为a StepExecutionContext(更详细的命名JobParameterExecutionContextCopyListener); 如果你的工作步骤不完全相互独立,你会发现你经常使用这些.

否则,您将使用更复杂的方案(如JMS队列或(天堂禁止)硬编码文件位置)在步骤之间传递数据.

至于在上下文中传递的数据的大小,我还建议你保持小的(但我没有任何具体细节)

  • 该死,五年过去了,这个问题仍然具有吸引力。春季批次的路要走:) (4认同)
  • 这可以通过以下文档+示例来确认:http://docs.spring.io/spring-batch/trunk/reference/html/patterns.html#passingDataToFutureSteps (3认同)

Jea*_*end 30

从一个步骤,您可以将数据放入StepExecutionContext.然后,向监听器,你可以从促进数据StepExecutionContextJobExecutionContext.

JobExecutionContext可以在以下所有步骤中使用.

笨拙:数据必须简短.这些上下文JobRepository通过序列化保存,长度有限(如果我记得很清楚,则为2500个字符).

因此,这些上下文很适合共享字符串或简单值,但不适用于共享集合或大量数据.

共享大量数据并不是Spring Batch的理念.Spring Batch是一组不同的操作,而不是一个巨大的业务处理单元.

  • 您将如何共享潜在的大数据,例如在集合中?我的 itemProcessor 生成一个列表(要删除的记录),我需要将该列表向下传递以供 tasklet 处理(执行实际的记录删除)。谢谢 (3认同)

Nen*_*zic 17

我会说你有3个选择:

  1. 使用StepContext和推广它JobContext并且您可以从每个步骤访问它,您必须遵守规定服从限制
  2. 创建@JobScopebean并向该bean添加数据,@Autowire在需要的地方使用它(缺点是它是内存中的结构,如果作业失败,数据丢失,则会导致重启性问题)
  3. 我们需要跨步骤处理更大的数据集(读取csv中的每一行并写入DB,从DB读取,聚合并发送到API)所以我们决定在新表中将数据建模在与Spring批量元表相同的DB中,保持idsJobContext需要时进行访问并在作业成功完成时删除该临时表.

  • 关于你的2选项.我可以用这种方式从writer类中读取类的bean集吗? (2认同)

小智 7

您可以使用Java Bean对象

  1. 执行一步
  2. 将结果存储在Java对象中
  3. 下一步将引用相同的java对象来获取步骤1存储的结果

通过这种方式,您可以根据需要存储大量数据

  • 在下一步中,我将如何从第一步获得对象.问题的关键在于 (16认同)
  • @Elbek Autowire吧.您在第一步中的类具有POJO自动装配并设置数据,并且您在第二步中的类也具有相同的自动装配对象(除非您正在进行远程分区,否则应该是相同的实例)并使用getter. (2认同)
  • @ POJO的组件,@ Autowired + Setters的第一步,@ Autowired + Getters.在Tasklets中也使用JobScope注释. (2认同)

Ziy*_*iya 6

这是我保存一个可以通过整个步骤访问的对象的操作。

  1. 创建了一个侦听器,用于在作业上下文中设置对象
@Component("myJobListener")
public class MyJobListener implements JobExecutionListener {

    public void beforeJob(JobExecution jobExecution) {

        String myValue = someService.getValue();
        jobExecution.getExecutionContext().putString("MY_VALUE", myValue);
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 在作业上下文中定义了侦听器
<listeners>
         <listener ref="myJobListener"/>
</listeners>
Run Code Online (Sandbox Code Playgroud)
  1. 使用BeforeStep注释在步骤中消耗值
@BeforeStep
public void initializeValues(StepExecution stepExecution) {

String value = stepExecution.getJobExecution().getExecutionContext().getString("MY_VALUE");

}
Run Code Online (Sandbox Code Playgroud)


Kor*_*gay 6

另一种非常简单的方法,留在这里以供将来参考:

class MyTasklet implements Tasklet {
    @Override
    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) {
        getExecutionContext().put("foo", "bar");
    }
}
Run Code Online (Sandbox Code Playgroud)

class MyOtherTasklet implements Tasklet {
    @Override
    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) {
        getExecutionContext().get("foo");
    }   
}
Run Code Online (Sandbox Code Playgroud)

getExecutionContext这是:

ExecutionContext getExecutionContext(ChunkContext chunkContext) {
    return chunkContext.getStepContext()
                       .getStepExecution()
                       .getJobExecution()
                       .getExecutionContext();
}     
Run Code Online (Sandbox Code Playgroud)

将其作为方法放入超类、接口中default,或者直接粘贴到您的Tasklets.


Val*_* K. 5

您可以将数据存储在简单对象中。喜欢:

AnyObject yourObject = new AnyObject();

public Job build(Step step1, Step step2) {
    return jobBuilderFactory.get("jobName")
            .incrementer(new RunIdIncrementer())
            .start(step1)
            .next(step2)
            .build();
}

public Step step1() {
    return stepBuilderFactory.get("step1Name")
            .<Some, Any> chunk(someInteger1)
            .reader(itemReader1())
            .processor(itemProcessor1())
            .writer(itemWriter1(yourObject))
            .build();
}

public Step step2() {
    return stepBuilderFactory.get("step2Name")
            .<Some, Any> chunk(someInteger2)
            .reader(itemReader2())
            .processor(itemProcessor2(yourObject))
            .writer(itemWriter2())
            .build();
}
Run Code Online (Sandbox Code Playgroud)

只需在编写器或任何其他方法中向对象添加数据,并在下一步的任何阶段获取它