使用Spring批处理同时(同时)处理通过ItemReader读取的多个对象

时间:2018-10-28 13:34:08

标签: spring-boot spring-batch batch-processing spring-batch-admin spring-boot-admin

我试图从数据库中读取数据,并同时在每个对象上运行进程。

  

我的配置如下,

@Bean
public Job job() {
    return jobBuilderFactory.get("job").incrementer(new RunIdIncrementer()).listener(new Listener(videoDao))
            .flow(step1()).end().build();
}

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
            .<VideosDTO, VideosDTO>chunk(3)
            .reader(databaseVideoItemReader(null))
            .processor(new Processor())
            .writer(new Writer(videoDao))
            .build();
}



 @Bean
 @StepScope
ItemReader<VideosDTO> databaseVideoItemReader(@Value("#{jobParameters[userId]}") String userId) {
    logger.info("Fetching videos for userId:"+userId);
    JdbcCursorItemReader<VideosDTO> databaseReader = new JdbcCursorItemReader<>();
    databaseReader.setDataSource(dataSource);
    databaseReader.setSql("SELECT * FROM voc.t_videos where user_id="+userId+"AND job_success_ind='N'");
    databaseReader.setRowMapper(new BeanPropertyRowMapper<>(VideosDTO.class));
   // databaseReader.open(new ExecutionContext());
   ExecutionContext executionContext= new ExecutionContext();
   executionContext.size();
   databaseReader.open(executionContext);

    return databaseReader;
}
  

我的项目处理如下,

@Override
public VideosDTO process(VideosDTO videosDTO) throws Exception {
    log.info("processing........" + videosDTO.getVideoUrl());

    try {
        Process p = Runtime.getRuntime()
                .exec("C:\\Program Files\\Git\\bin\\bash.exe " + "D:\\DRM\\script.sh " + videosDTO.getVideoUrl());
        // .exec("D:\\PortableGit\\bin\\bash.exe
        // D:\\Vocabimate_Files\\script.sh "+videosDTO.getVideoUrl());
        // Thread.sleep(1000);
        Thread.sleep(1000);
        p.destroy();
        try {
            p.waitFor();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try (InputStream is = p.getErrorStream()) {
            int in = -1;
            while ((in = is.read()) != -1) {
                System.out.print((char) in);
            }
        }
        try (InputStream is = p.getInputStream()) {
            int in = -1;
            while ((in = is.read()) != -1) {
                System.out.print((char) in);
            }
        }
    } catch (IOException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
    }

    return videosDTO;
}
  

作者如下:

    @Override
public void write(List<? extends VideosDTO>videosList) throws Exception {

    for(VideosDTO vid:videosList){
        log.info("writting...."+vid.getVideoUrl());
    }

}
  

假设首先从数据库中获取3个对象,则此代码   完成第一个对象的过程,第二个对象比第三个对象   开始写我想同时在三个对象上运行进程   同时执行写操作。

有什么办法吗?

2 个答案:

答案 0 :(得分:1)

在不深入了解自定义阅读器/处理器/书写器的详细信息的情况下,我认为您要寻找的是a multi-threaded Step

如上面链接的文档中所述,为了使您的步骤成为多线程(意味着在单独的线程中读取/处理/写入每个块),您首先需要注册SimpleAsyncTaskExecutor

@Bean
public TaskExecutor taskExecutor(){
    return new SimpleAsyncTaskExecutor("myAsyncTaskExecutor");
}

,然后在您的Step的构建器中注册此任务执行器:

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
            .<VideosDTO, VideosDTO>chunk(3)
            .reader(databaseVideoItemReader(null))
            .processor(new Processor())
            .writer(new Writer(videoDao))
            //making the Step multi-threaded
            .taskExecutor(taskExecutor())
            .build();
}

答案 1 :(得分:1)

使用@dimitrisli建议的多线程步骤是可行的方法。除此之外,另一种方法是使用AsyncItemProcessor(与AsyncItemWriter结合使用)。

可以在以下位置找到类似的用例(从处理器异步调用剩余端点):https://stackoverflow.com/a/52309260/5019386,其中提供了更多详细信息。

希望这会有所帮助。