Spring batch 复杂批处理{read-write-split-write}
我有这样的情况——我有一个文件,其中每一行都包含一个文件名或目录名以及操作状态。此文件可能包含数千行。 然后,我应该将文件或目录的名称及其状态写入数据库。最后,我必须写入一个新文件,但是如果一个项目是一个目录,我必须找到这个目录中的所有文件,并写入这些文件的名称,而不是目录名 我认为这是两步工作,第一步是从文件中读取,然后写入数据库,并将项目并行地保存为内存列表中的项目。第二步是从这个内存列表中读取,如果这是一个目录,用读取器中的文件名替换它,然后写入文件 我担心的一件事是在台阶之间夹着成千上万的物体Spring batch 复杂批处理{read-write-split-write},spring-batch,Spring Batch,我有这样的情况——我有一个文件,其中每一行都包含一个文件名或目录名以及操作状态。此文件可能包含数千行。 然后,我应该将文件或目录的名称及其状态写入数据库。最后,我必须写入一个新文件,但是如果一个项目是一个目录,我必须找到这个目录中的所有文件,并写入这些文件的名称,而不是目录名 我认为这是两步工作,第一步是从文件中读取,然后写入数据库,并将项目并行地保存为内存列表中的项目。第二步是从这个内存列表中读取,如果这是一个目录,用读取器中的文件名替换它,然后写入文件 我担心的一件事是在台阶之间夹着成千上万
有谁能提出更优雅的解决方案吗?我认为你不需要两个步骤。您可以使用单个步骤 你的读者将保持不变 您可以使用processor将目录扩展到文件,也可以在ItemReader中实现 使用委托项编写器并写入数据库和新文件。 下面是批配置示例
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
// tag::readerwriterprocessor[]
@Bean
public FlatFileItemReader<String> reader() {
FlatFileItemReader<String> reader = new FlatFileItemReader<String>();
reader.setResource(new PathResource("MyFile"));
reader.setLineMapper(new PassThroughLineMapper());
return reader;
}
@Bean
public CompositeItemReader<String> cpReader(){
final CompositeItemReader<String> reader = new CompositeItemReader<>();
reader.setItemReader(reader());
return reader;
}
@Bean
public CompositeItemWriter<String> cpWriter(){
final CompositeItemWriter<String> delegator = new CompositeItemWriter<>();
delegator.setDelegates(Arrays.asList(fileWriter(), dbWriter()));
return cpWriter();
}
@Bean
public FlatFileItemWriter<String> fileWriter(){
return null;
}
@Bean
public JdbcBatchItemWriter<String> dbWriter(){
return null;
}
@Bean
public ItemWriter<String> writer() {
final ItemWriter<String> writer = new ItemWriter<String>() {
@Override
public void write(List<? extends String> items) throws Exception {
items.forEach(System.out::println);
}
};
return writer;
}
@Bean
public Job kpJob() {
return jobBuilderFactory.get("kpJob").incrementer(new RunIdIncrementer()).start(step1()).build();
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1Child").<String, String>chunk(10).reader(cpReader()).writer(cpWriter()).stream(reader()).build();
}
}
复合式电子阅读器
public class CompositeItemReader implements ItemCountAware, ItemReader<String> {
private ItemReader<String> itemReader;
private int count = 1;
private final LinkedList<String> files = new LinkedList<>();
public ItemReader<String> getItemReader() {
return itemReader;
}
public void setItemReader(ItemReader<String> itemReader) {
this.itemReader = itemReader;
}
@Override
public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
return readFile();
}
private String readFile()
throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (files.size() == 0) {
final String item = itemReader.read();
if (item == null) {
return null;
} else {
Path path = Paths.get(item);
if (Files.isDirectory(path)) {
files.addAll((Collection<? extends String>) Files.walk(path, 1).map(Path::toString)
.collect(Collectors.toList()));
} else {
files.add(path.toString());
}
}
}
return files.poll();
}
@Override
public void setItemCount(int count) {
this.count = count;
}
}
希望这些基本信息能够继续。所以,如果有人好奇,我想到了下一个解决方案:在数据库中创建一个新表,用于按原样存储文件中的记录,因此,如果一行包含filename,则存储它,如果一行包含dirname,则也存储它。然后在这个表的帮助下,我可以连接到我的目标表,从特定目录中获取文件名列表 所以,第一步就是从文件中读取并存储到两个表中——新表和目标表
第二步是使用一个只返回文件名的查询从数据库中读取数据,并将这些记录写入文件,而不进行任何拆分/扩展,因为这是由查询完成的 你能详细说明一下吗?例如,我没有得到,因为我必须写入db目录名和dir的文件扩展文件名,如何使用您的解决方案实现这一点?