Spring Boot 批处理调度程序运行一次

Posted

技术标签:

【中文标题】Spring Boot 批处理调度程序运行一次【英文标题】:Spring boot batch scheduler run once 【发布时间】:2019-09-22 20:29:04 【问题描述】:

我在 2.1.4 版本开始学习 Spring Boot Batch

我想在调度程序中运行我的作业,而这个作业只运行一次。我的意思是 ItemProcessor 和 ItemWriter 只运行一次。 ItemReader 每次都运行。任何人都知道我做错了什么。将来,我想将调度程序更改为 Java WatchService 并将 filePath 传递给作业,但现在 filePath 的参数就像函数参数中的字符串。这是我的代码:

这是我的读者:

@Component
public class UserReaderImpl  
    @StepScope
    public ItemReader<UserCsvStructure> read(String filepath) 
        FlatFileItemReader<UserCsvStructure> reader = new FlatFileItemReader();
        reader.setLinesToSkip(1);
        reader.setResource(new FileSystemResource(filepath));
        reader.setLineMapper(new DefaultLineMapper<UserCsvStructure>() 
            
                setLineTokenizer(new DelimitedLineTokenizer() 
                    
                        setNames(new String[]"firstName","lastName","email");
                    
                );
                setFieldSetMapper(new BeanWrapperFieldSetMapper<UserCsvStructure>() 
                    
                        setTargetType(UserCsvStructure.class);
                    
                );
            
        );
        return reader;
    

这在我的 ItemProcessor 中

@StepScope
@Component
public class UserProcessorImpl implements ItemProcessor<UserCsvStructure, User> 
@Override
public User process(UserCsvStructure userCsvStructure) throws Exception 
    return User.builder()
            .email(userCsvStructure.getEmail())
            .firstName(userCsvStructure.getFirstName())
            .lastName(userCsvStructure.getLastName())
            .build();


这是我的 ItemWriter

@Component
@StepScope
public class UserWriterImpl implements ItemWriter<User>
@Autowired
private UserRepository userRepository;

@Override
public void write(List<? extends User> list) throws Exception 
    System.out.println(list);
    userRepository.saveAll(list);


这是我的配置

@Component
public class UserBatchCsvConfig 

@Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;

@Autowired
private UserReaderImpl userReader;

@Autowired
private UserWriterImpl userWriter;

@Autowired
private UserProcessorImpl userProcessor;

public Job csvFileToDatabaseJob(UserJobCompletionNotificationListener listener, String fileName) 
    return jobBuilderFactory.get("userCsvProcess")
            .incrementer(new RunIdIncrementer())
            .listener(listener)
            .flow(csvFileToDatabaseStep(fileName))
            .end()
            .build();


private Step csvFileToDatabaseStep(String fileName) 
    return stepBuilderFactory.get("userCsvProcess")
            .<UserCsvStructure, User>chunk(1)
            .reader(userReader.read(fileName))
            .processor(userProcessor)
            .writer(userWriter)
            .build();



最后一节课是我的调度器:

@Component
public class UserCsvProcessor 

@Autowired
private JobLauncher jobLauncher;

@Autowired
private UserBatchCsvConfig job;

@Autowired
private UserJobCompletionNotificationListener userJobCompletionNotificationListener;

@Scheduled(fixedDelay = 10000)
public void runJob() throws Exception 
    jobLauncher.run(job.csvFileToDatabaseJob(userJobCompletionNotificationListener, "C:\\Users\\Anik\\Desktop\\angular\\test.csv"), new JobParameters());


【问题讨论】:

I mean ItemProcessor and ItemWriter run only once. ItemReader runs every time.: 不清楚。你想达到什么目的? 我多次尝试运行该作业。每次,我都会收到一个错误,因为 spring batch 告诉我这项工作已经在运行。我通过添加如下参数来实现它 【参考方案1】:

我知道我应该在我的代码中添加什么 在 UserCsvProcessor 类中,我需要将计划函数更改为:

@Scheduled(fixedDelay = 10000)
public void runJob() throws Exception 
    JobParameters params = new JobParametersBuilder()
            .addString("JobID", String.valueOf(System.currentTimeMillis()))
            .toJobParameters();
    jobLauncher.run(job.csvFileToDatabaseJob(userJobCompletionNotificationListener, "C:\\Users\\Anik\\Desktop\\angular\\test.csv"), params);

如果有人有其他想法或更好的想法,请添加答案

【讨论】:

【参考方案2】:

使用 @Scheduled 注释中的配置,您指示每 10 秒执行一次。因此,当您的第一次执行完成时,它将等待 10 秒,然后再次执行,依此类推。

@Scheduled(fixedDelay = 10000)

如果你想执行一次(我猜是一天一次),你可以在 @Scheduled 注释中使用 cron 表达式。检查下面的示例,其中 cron 表达式指示该方法应在每天上午 10:15 执行。

@Scheduled(cron = "0 15 10 * * *")

如果您想每月/每年运行一次,您可以处理 cron 表达式来执行此操作。 此外,您可以使用以下内容从配置文件中读取该表达式:

@Scheduled(cron = "$cron.expression")

【讨论】:

这不是日程安排的问题,而是批处理作业的问题。看我上面的回答 我现在明白了。就我而言,我必须对某些批次做同样的事情。

以上是关于Spring Boot 批处理调度程序运行一次的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Boot 和 Flyway 为 Quartz 调度程序设置数据库模式?

windows调度程序每x分钟运行一次批处理脚本(.bat)? [复制]

Spring Boot 中的调度程序 Servlet

在 Spring Boot 中使用多个调度程序 Servlet/Web 上下文

如何防止我的 Spring Boot Batch 应用程序在执行测试时运行?

用Spring Boot开发命令行执行程序