首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >弹簧批处理重复步骤结束于永续循环。

弹簧批处理重复步骤结束于永续循环。
EN

Stack Overflow用户
提问于 2016-08-10 11:10:49
回答 2查看 8.3K关注 0票数 5

我有一份春季批次工作,我想做以下工作.

代码语言:javascript
复制
Step 1 - 
   Tasklet - Create a list of dates, store the list of dates in the job execution context.

Step 2 - 
   JDBC Item Reader - Get list of dates from job execution context.
                      Get element(0) in dates list. Use is as input for jdbc query. 
                      Store element(0) date is job execution context 
                      Remove element(0) date from list of dates
                      Store element(0) date in job execution context                 
   Flat File Item Writer - Get element(0) date from job execution context and use for file name.

Then using a job listener repeat step 2 until no remaining dates in the list of dates.

我已经创建了这个作业,第一次执行第二步还行,但是第二步并没有像我想要的那样重复。我之所以知道这一点,是因为当我通过代码进行调试时,它只会中断步骤2的初始运行。

但是,它确实会像下面这样继续给我消息,就好像它正在运行步骤2一样,即使我知道它不是。

代码语言:javascript
复制
2016-08-10 22:20:57.842  INFO 11784 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Duplicate step [readStgDbAndExportMasterListStep] detected in execution of job=[exportMasterListCsv]. If either step fails, both will be executed again on restart.
2016-08-10 22:20:57.846  INFO 11784 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [readStgDbAndExportMasterListStep]

这将以一个永无止境的循环结束。

有人能帮我弄清楚为什么我的stpe 2只运行一次吗?

提前感谢

我为我的代码添加了两个链接到PasteBin,以避免污染这个帖子。

http://pastebin.com/QhExNikm (Job )

http://pastebin.com/sscKKWRk (通用作业控制)

http://pastebin.com/Nn74zTpS (步骤执行侦听器)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-08-15 08:09:13

基于我们对Spring batch execute dynamically generated steps in a tasklet的讨论,我试图回答有关如何在实际执行作业之前访问jobParameter的问题。

我假设存在that调用,它将执行批处理。一般来说,这将需要采取以下步骤。1.接收rest调用及其参数的代码2.创建新的some上下文(有方法重用现有的上下文并再次启动作业,但在重用步骤、读者和作者时存在一些问题)。

最简单的解决方案是将从服务接收的作业参数存储为系统属性,然后在步骤3中构建作业时访问该属性。但是,如果多个用户同时启动作业,则可能会导致问题。

在加载参数时,还有其他方法将参数传递到loaded上下文中。但这取决于设置上下文的方式。例如,如果在步骤2中直接使用SpringBoot,则可以编写如下方法:

代码语言:javascript
复制
private int startJob(Properties jobParamsAsProps) {
  SpringApplication springApp = new SpringApplication(.. my config classes ..);
  springApp.setDefaultProperties(jobParamsAsProps);

  ConfigurableApplicationContext context = springApp.run();
  ExitCodeGenerator exitCodeGen = context.getBean(ExitCodeGenerator.class);
  int code = exitCodeGen.getExitCode();
  context.close();
  return cod;
}

通过这种方式,您可以使用标准值或ConfigurationProperties注释正常地访问这些属性。

票数 1
EN

Stack Overflow用户

发布于 2016-08-10 17:37:38

从您的问题和代码中,我推断,根据您检索的日期的数量(在实际作业开始之前发生的情况),您将对有日期的时间执行一个步骤。

我建议改变设计。创建一个java类,将日期作为列表获取,并根据该列表动态创建您的步骤。就像这样:

代码语言:javascript
复制
@EnableBatchProcessing
public class JobConfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;  

    @Autowired
    private JobDatesCreator jobDatesCreator;

    @Bean
    public Job executeMyJob() {
        List<Step> steps = new ArrayList<Step>();
        for (String date : jobDatesCreator.getDates()) {
            steps.add(createStep(date));
        }

        return jobBuilderFactory.get("executeMyJob")
                .start(createParallelFlow(steps))
                .end()
                .build();       
    }

    private Step createStep(String date){
        return stepBuilderFactory.get("readStgDbAndExportMasterListStep" + date)
                .chunk(your_chunksize)
                .reader(your_reader)
                .processor(your_processor)
                .writer(your_writer)                                
                .build();       
    }   

    private Flow createParallelFlow(List<Step> steps) {
        SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
        // max multithreading = -1, no multithreading = 1, smart size = steps.size()
        taskExecutor.setConcurrencyLimit(1); 

        List<Flow> flows = steps.stream()
                .map(step -> new FlowBuilder<Flow>("flow_" + step.getName()).start(step).build())
                .collect(Collectors.toList());

        return new FlowBuilder<SimpleFlow>("parallelStepsFlow")
                .split(taskExecutor)
                .add(flows.toArray(new Flow[flows.size()]))
                .build();
    }  
}

编辑:添加了"jobParameter“输入(也略有不同)

在类路径的某个位置添加以下示例.properties文件:

代码语言:javascript
复制
sql.statement="select * from awesome"

并将以下注释添加到JobDatesCreator类中

代码语言:javascript
复制
@PropertySource("classpath:example.properties")

您还可以提供特定的sql语句作为命令行参数。在春季文件中:

您可以使用特定的命令行开关启动(例如,java -jar app.jar -name=“Spring”)。

有关此问题的更多信息,请参见http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

获取日期的类(为什么要使用tasklet进行此操作?):

代码语言:javascript
复制
@PropertySource("classpath:example.properties")
public class JobDatesCreator {

    @Value("${sql.statement}")
    private String sqlStatement;

    @Autowired
    private CommonExportFromStagingDbJobConfig commonJobConfig; 

    private List<String> dates; 

    @PostConstruct
    private void init(){
        // Execute your logic here for getting the data you need.
        JdbcTemplate jdbcTemplate = new JdbcTemplate(commonJobConfig.onlineStagingDb);
        // acces to your sql statement provided in a property file or as a command line argument
        System.out.println("This is the sql statement I provided in my external property: " + sqlStatement);

        // for now..
        dates = new ArrayList<>();
        dates.add("date 1");
        dates.add("date 2");
    }

    public List<String> getDates() {
        return dates;
    }

    public void setDates(List<String> dates) {
        this.dates = dates;
    }
}

我还注意到,您有很多重复的代码,可以很容易地重构。现在,对于每一位作家来说,都有这样的东西:

代码语言:javascript
复制
@Bean
public FlatFileItemWriter<MasterList> division10MasterListFileWriter() {
    FlatFileItemWriter<MasterList> writer = new FlatFileItemWriter<>();
    writer.setResource(new FileSystemResource(new File(outDir, MerchHierarchyConstants.DIVISION_NO_10 )));
    writer.setHeaderCallback(masterListFlatFileHeaderCallback());
    writer.setLineAggregator(masterListFormatterLineAggregator());
    return writer;
}

请考虑使用类似的方法:

代码语言:javascript
复制
public FlatFileItemWriter<MasterList> divisionMasterListFileWriter(String divisionNumber) {
    FlatFileItemWriter<MasterList> writer = new FlatFileItemWriter<>();
    writer.setResource(new FileSystemResource(new File(outDir, divisionNumber )));
    writer.setHeaderCallback(masterListFlatFileHeaderCallback());
    writer.setLineAggregator(masterListFormatterLineAggregator());
    return writer;
}

由于并不是所有的代码都可以正确地复制您的问题,因此这个答案是解决问题的建议/指示。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38871808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档