我正在评估特定项目的春季批处理,并且在网上进行了大量搜索之后,我一直无法找到满足我要求的春季批处理解决方案。
我想知道spring batch是否能够在单个作业中读取由不同格式组成的多个CSV文件?例如,假设Person.csv和Address.csv都由不同的格式组成,但彼此依赖
我需要阅读,进行数据更正(例如toUpperCase等)并验证每条记录。
如果发生验证错误,我需要将错误记录到某种对象数组中,以便在验证完成后稍后将其提供给最终用户,以通过电子邮件将其更正。
一旦两个文件中的所有数据均已验证并且两个文件中均未发生验证错误,请继续执行批处理写入器。如果两个文件中的任何一个发生任何错误,我都需要停止整个作业。如果在发生错误时编写者已经开始写数据库,则无论该相反文件中是否存在错误,都需要回滚整个作业。
如果任何一个CSV验证错误都无法插入两个CSV文件中的任何一个。必须将错误告知最终用户。错误将用于在重新处理文件之前进行任何必要的更正。
SpringBoot 2中的Spring批处理能够做到这一点吗?
示例
Person.csv
BatchId, personId, firstName, lastName
Address.csv
BatchId, personId, address1
在上面的示例中,两个文件之间的关系是batchId和personId。如果两个文件中的任何一个都存在验证错误,则我必须使整个批处理都失败。我想对两个文件都完成验证,以便我可以对所有错误进行响应,但不能写入数据库。
答案 0 :(得分:1)
我想知道spring batch是否能够在单个作业中读取由不同格式组成的多个CSV文件?
是的,您可以具有多个步骤的单个作业,每个步骤处理给定类型的文件。关键是如何设计工作。您可以应用的一种技术是使用登台表。批处理作业可以创建临时登台表,在该表中加载所有需要的数据,然后在完成后将其删除。
根据您的情况,您可以分两个步骤将每个文件加载到特定的登台表中。每个步骤都可以将验证逻辑应用于每个文件。如果这些步骤之一失败,您将使作业失败。登台表可以具有用于无效记录的标记列(这对于报告很有用)。
完成这两个准备步骤后,您就可以在另一个步骤中从两个登台表中读取数据,并对联接的数据应用交叉验证规则(例如,从两个表中选择并通过BatchId
和{{ 1}})。如果此步骤失败,您将使作业失败。否则,您将在适当的地方写入数据。
此技术的优点在于,在整个作业过程中,临时表中都有数据。因此,每当验证步骤失败时,您都可以使用流程将失败的步骤重定向到“报告步骤”(读取无效数据并发送报告),然后使作业失败。这是一个您可以使用的独立示例:
PersonId
要使步骤之一失败,请将退出状态设置为import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class FlowJobSample {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public Step personLoadingStep() {
return steps.get("personLoadingStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("personLoadingStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step addressLoadingStep() {
return steps.get("addressLoadingStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("addressLoadingStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step crossValidationStep() {
return steps.get("crossValidationStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("crossValidationStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step reportingStep() {
return steps.get("reportingStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("reportingStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Job job() {
return jobs.get("job")
.start(personLoadingStep()).on("INVALID").to(reportingStep())
.from(personLoadingStep()).on("*").to(addressLoadingStep())
.from(addressLoadingStep()).on("INVALID").to(reportingStep())
.from(addressLoadingStep()).on("*").to(crossValidationStep())
.from(crossValidationStep()).on("INVALID").to(reportingStep())
.from(crossValidationStep()).on("*").end()
.from(reportingStep()).on("*").fail()
.build()
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(FlowJobSample.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
}
,例如:
INVALID
我希望这会有所帮助。