【问题标题】:Spring Batch: Job can't be started with different JobParameters and JobParameters can't be accessedSpring Batch:无法使用不同的JobParameters启动Job并且无法访问JobParameters
【发布时间】:2021-02-11 15:46:43
【问题描述】:

我遇到了 Spring Batch 的问题。两者都是关于通过命令行传入的 JobParameters。

第一期:

我正在使用 Eclipse 来开发我的应用程序并对其进行测试。因此,我在Run Configurations 中添加了Program arguments。这些论点是:

-ts=${current_date} -path="file.csv"

运行应用程序将引发异常。例外是:

Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: 
A job instance already exists and is complete for parameters={ts=20210211_1631, path=file.csv}.  
If you want to run this job again, change the parameters.

正如您所见,每次执行的 JobParameters 应该是不同的,因为其中一个参数是每分钟都在变化的时间戳。我看过这个问题Spring Batch: execute same job with different parameters,但这里的解决方案是为每个作业执行设置一个新名称(例如name + System.currentTimeMillis())。这个问题还有其他解决方案吗?我不想在每次执行作业时为其创建一个“随机”名称。我的工作是这样实现的:

@Bean(name = "inJob")
public Job inJob(JobRepository jobRepository) {
    return jobBuilderFactory.get("inJob")
            .repository(jobRepository)
            .incrementer(new RunIdIncrementer())
            .start(truncateTable())
            .next(loadCsv())
            .next(updateType())
            .build();
}

我正在使用 JobRepository 的自定义实现将元数据存储在不同的数据库架构中:

@Override
public JobRepository createJobRepository() throws Exception {
    JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
    factory.setDataSource(dataSource);
    factory.setTransactionManager(transactionManager);
    factory.setTablePrefix("logging.BATCH_");
    return factory.getObject();
}

第二期:

我的第二个问题是访问 JobParameters。上述参数之一是我要在 FlatFileItemReader 中使用的文件路径:

@Bean(name = "inReader")
@StepScope
public FlatFileItemReader<CsvInfile> inReader() {       
    FlatFileItemReader<CsvInfile> reader = new FlatFileItemReader<CsvInfile>();
    reader.setResource(new FileSystemResource(path));
    DefaultLineMapper<CsvInfile> lineMapper = new DefaultLineMapper<>();
    lineMapper.setFieldSetMapper(new CsvInfileFieldMapper());
    DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
    tokenizer.setDelimiter("|");
    tokenizer.setNames(ccn.names);
    lineMapper.setLineTokenizer(tokenizer);
    reader.setLineMapper(lineMapper);
    reader.setLinesToSkip(1);
    reader.open(new ExecutionContext());
    return reader;
}

为了从 JobParameters 中获取路径,我使用了 BeforeStep 注释来加载 JobParameters 并将它们复制到局部变量中。不幸的是,这不起作用。变量将是null,执行失败,因为文件无法打开。

private String path;

@BeforeStep
public void beforeStep(StepExecution stepExecution) {
    JobParameters jobParameters = stepExecution.getJobParameters();
    this.path = jobParameters.getString("path");
}

如何在阅读器中访问 JobParameters?我想将文件路径作为命令行参数传入,然后读取这个文件。

【问题讨论】:

    标签: java spring spring-batch


    【解决方案1】:

    第一个问题:这个问题还有其他解决方案吗?

    您当前的日期是每分钟解析一次,因此如果您在那一分钟内多次运行您的作业,则已经有一个具有相同参数的作业实例,因此会出现问题。您的ts 参数的精度应为一秒(或更少,如果需要)。

    第二个问题:如何在阅读器中访问 JobParameters?我想将文件路径作为命令行参数传入,然后读取这个文件。

    你不需要那个beforeStep 方法。您可以在 bean 定义中后期绑定作业参数,如下所示:

    @Bean(name = "inReader")
    @StepScope
    public FlatFileItemReader<CsvInfile> inReader(@Value("#{jobParameters['path']}") String path) {       
        FlatFileItemReader<CsvInfile> reader = new FlatFileItemReader<CsvInfile>();
        reader.setResource(new FileSystemResource(path));
        // ...
        return reader;
    }
    

    如果您将path 作为作业参数传递,这将在您的阅读器定义中注入文件路径,例如:

    java -jar myjob.jar path=/absolute/path/to/your/file
    

    参考文档的Late Binding of Job and Step Attributes 部分对此进行了说明。

    【讨论】:

    • 我知道我的时间戳参数每分钟都在变化。如果我等待超过一分钟,问题仍然存在,因此时间戳已更改。
    • 好吧,我将参数从 -path=xxx 更改为 path=xxx,现在它按预期工作了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 2013-07-07
    • 2013-03-24
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    相关资源
    最近更新 更多