Spring 批处理:无法使用不同的 JobParameters 启动作业,并且无法访问 JobParameters
Spring Batch: Job can't be started with different JobParameters and JobParameters can't be accessed
我必须解决 Spring 批处理的问题。两者都与通过命令行传入的 JobParameters 有关。
第一期:
我正在使用 Eclipse 开发我的应用程序并对其进行测试。因此,我将 Program arguments
添加到 Run Configurations
。这些参数是:
-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()
)。这个问题还有其他解决方案吗?我不想在每次执行作业时都为它创建一个 'random' 名称。我的工作是这样实现的:
@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");
}
如何访问 reader 中的 JobParameters?我想传入文件路径作为命令行参数,然后读取这个文件。
First issue: Is there another solution to this problem?
您当前的日期是每分钟解析一次,因此如果您在那一分钟内多次 运行 您的作业,则已经有一个具有相同参数的作业实例,因此会出现问题。您的 ts
参数的精度应为一秒(如果需要,可以更小)。
Second issue: How can I access the JobParameters within my reader? I want to pass in the file path as command line argument and then read this file.
您不需要那种 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
作为作业参数传递,这将在您的 reader 定义中注入文件路径,例如:
java -jar myjob.jar path=/absolute/path/to/your/file
参考文档的 Late Binding of Job and Step Attributes 部分对此进行了解释。
我必须解决 Spring 批处理的问题。两者都与通过命令行传入的 JobParameters 有关。
第一期:
我正在使用 Eclipse 开发我的应用程序并对其进行测试。因此,我将 Program arguments
添加到 Run Configurations
。这些参数是:
-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()
)。这个问题还有其他解决方案吗?我不想在每次执行作业时都为它创建一个 'random' 名称。我的工作是这样实现的:
@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");
}
如何访问 reader 中的 JobParameters?我想传入文件路径作为命令行参数,然后读取这个文件。
First issue: Is there another solution to this problem?
您当前的日期是每分钟解析一次,因此如果您在那一分钟内多次 运行 您的作业,则已经有一个具有相同参数的作业实例,因此会出现问题。您的 ts
参数的精度应为一秒(如果需要,可以更小)。
Second issue: How can I access the JobParameters within my reader? I want to pass in the file path as command line argument and then read this file.
您不需要那种 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
作为作业参数传递,这将在您的 reader 定义中注入文件路径,例如:
java -jar myjob.jar path=/absolute/path/to/your/file
参考文档的 Late Binding of Job and Step Attributes 部分对此进行了解释。