在实际项目开发的中,经常会遇到这样的场景:由于数据量很大,会将数据批量导入到多个文件中,从而避免因单个文件数据量过大而带来不好的影响;这种场景下主要关注两个因素:第一,控制每一个文件的写入条数,一旦要写的数据超过这个条数,就会再创建一个新的格式完全一样的文件;第二,多文件的文件名称要保持一致,且呈递增格式。
SpringBatch提供了MultiResourceItemWriter
如图,该组件主要由三元素构成,其具体作用如下:
这里需要指出的是,程序中指定的Resource是原始设置的文件路径+名称,如D:/demo.txt;而使用MultiResourceItemWriter写入到多文件后,就会对该文件名成就行一定的修改,若采用默认的名称后缀生成器,最终的文件名称就是D:/demo.txt.1。
这里核心的ItemWriter功能,ItemReader和ItemProcess同上节SpringBatch批处理之导出数据到XML文件 。
如下面的代码,只需使用MultiResourceItemWriter替换ItemWriter,然后设置好每个文件的大小,代理的实际写bean,资源路径和文件后缀名生成器等。
@Bean
@StepScope
MultiResourceItemWriter multiXmlFileItemWriter() {
MultiResourceItemWriter writer = new MultiResourceItemWriter();
//设置每个文件写入文件条数大小
writer.setItemCountLimitPerResource(10);
//设置实际写如的ItemWriter
writer.setDelegate(registrationToXmlItemWriter());
//设置文件资源路径
writer.setResource(new FileSystemResource("D://xml.xml"));
//设置文件后缀名生成器,自定义
writer.setResourceSuffixCreator(new FileNameCreator());
return writer;
}
下面是具体的文件写使用的方式:这里就以导出数据到XML文件为例。
@Bean
StaxEventItemWriter registrationToXmlItemWriter() {
StaxEventItemWriter writer = new StaxEventItemWriter<>();
writer.setEncoding("UTF-16");
writer.setRootTagName("RegistrationFile");
writer.setHeaderCallback(new HeaderCallback());
writer.setFooterCallback(new FooterCallback());
writer.setMarshaller(marshaller());
return writer;
}
以上就是数据导入到多文件的基本实现流程,SpringBatch提供的开箱即用功能,的确很方便。
基于以上关于MultiResourceItemWriter的介绍,我们可以很方便的完成项目中的需求。同时也会遇到各种问题,这里介绍我在实际开发中遇到的两个问题。
我们知道SpringBatch批处理是的最小处理单位是Chunk(单位:批),它的事务控制也是以批为单位,一批数据是放在一起进行读和写操作。如下代码,设置chunk为1000。
@Bean
Step registrationToXmlStep(ItemReader registrationToXmlItemReader,
MultiResourceItemWriter multiXmlFileItemWriter,
StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("registrationToXmlStep")
//设置批的大小1000
.chunk(1000)
.reader(registrationToXmlItemReader)
.writer(multiXmlFileItemWriter)
.build();
}
我们设置每个文件的ItemCountLimitPerResource属性时,就要考虑chunk的大小,若每个文件写入的条数小于chunk值时,这时候设置的ItemCountLimitPerResource属性就无效,每个文件的大小就是根据chunk的大小而定了。
所以ItemCountLimitPerResource的值要大于chunk的值,且前者时后者的整数倍。
多文件的文件名是根据index呈增量呈现的。如demo.txt.1,demo.txt.2,依次递推。
SpringBatch提供了ResourceSuffixCreator,可以根据具体需求实现自定义后缀名格式,如下代码:
public class CustomerResourceSuffixCreator implements ResourceSuffixCreator {
public SimpleResourceSuffixCreator() {
}
public String getSuffix(int index) {
return "_" + index;
}
}
值得注意的是无论是使用默认的,还是自定义的ResourceSuffixCreator,都是修改的文件的后缀名,最终的效果都是在文件名后面添加index。实际项目中往往要求的文件名都是在文件名内部进行递增index,而不是仅仅在修改后缀,如demo_1_user.txt,demo_2_user.txt,以此类推。这个时候ResourceSuffixCreator就不能满足我们的需求。
经过对源码的探究,发现可以自定义MultiResourceItemWriter来实现该需求,如ExtMultiResourceItemWriter
private File setResourceToDelegate() throws IOException {
//创建多文件文件名的方法A
String path = this.resource.getFile().getAbsolutePath() + this.suffixCreator.getSuffix(this.resourceIndex);
File file = new File(path);
this.delegate.setResource(new FileSystemResource(file));
return file;
}
上面的方法是MultiResourceItemWriter生成文件名的地方,我们只需要重新自定义ExtMultiResourceItemWriter,然后在上面生成文件名的方法处,根据需求生成相应的文件名称即可。
---------SpringBatch批处理电子书下载地址百度网盘
链接: https://pan.baidu.com/s/1kCDsHuOPXHGJ0EjWleDalw 提取码: vvra