SpringBatch批处理之导出数据到多文件

在实际项目开发的中,经常会遇到这样的场景:由于数据量很大,会将数据批量导入到多个文件中,从而避免因单个文件数据量过大而带来不好的影响;这种场景下主要关注两个因素:第一,控制每一个文件的写入条数,一旦要写的数据超过这个条数,就会再创建一个新的格式完全一样的文件;第二,多文件的文件名称要保持一致,且呈递增格式。

MultiResourceItemWriter

SpringBatch提供了MultiResourceItemWriter<T>组件,可以很便捷地将数据写入到多文件中。

如图,该组件主要由三元素构成,其具体作用如下:

  • Resource:指定文件路径和名称;
  • ItemCountLimitPerResource:每一个文件能够写入的最大条数;
  • ResourceSuffixCreator:文件名称后缀生成器,默认是SimpleResourceSuffixCreator,即在文件名追加(. + index);
  • ResourceAwareItemWriterItemStream:具体的文件写入实现类,如写入XML,TXT等。

这里需要指出的是,程序中指定的Resource是原始设置的文件路径+名称,如D:/demo.txt;而使用MultiResourceItemWriter写入到多文件后,就会对该文件名成就行一定的修改,若采用默认的名称后缀生成器,最终的文件名称就是D:/demo.txt.1。

实际开发流程

这里核心的ItemWriter功能,ItemReader和ItemProcess同上节SpringBatch批处理之导出数据到XML文件

如下面的代码,只需使用MultiResourceItemWriter替换ItemWriter,然后设置好每个文件的大小,代理的实际写bean,资源路径和文件后缀名生成器等。

@Bean
@StepScope
MultiResourceItemWriter<Registration> multiXmlFileItemWriter() {
    MultiResourceItemWriter<Registration> writer = new MultiResourceItemWriter<Registration>();
   //设置每个文件写入文件条数大小
    writer.setItemCountLimitPerResource(10);
    
   //设置实际写如的ItemWriter
    writer.setDelegate(registrationToXmlItemWriter());
    
   //设置文件资源路径
   writer.setResource(new FileSystemResource("D://xml.xml"));
   //设置文件后缀名生成器,自定义
   writer.setResourceSuffixCreator(new FileNameCreator());


   return writer;
}
下面是具体的文件写使用的方式:这里就以导出数据到XML文件为例。
@Bean
StaxEventItemWriter<Registration> registrationToXmlItemWriter() {
    StaxEventItemWriter<Registration> 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的介绍,我们可以很方便的完成项目中的需求。同时也会遇到各种问题,这里介绍我在实际开发中遇到的两个问题。

  1. ItemCountLimitPerResource设置无效:

我们知道SpringBatch批处理是的最小处理单位是Chunk(单位:批),它的事务控制也是以批为单位,一批数据是放在一起进行读和写操作。如下代码,设置chunk为1000。

@Bean
Step registrationToXmlStep(ItemReader<Registration> registrationToXmlItemReader,
                           MultiResourceItemWriter<Registration> multiXmlFileItemWriter,
                           StepBuilderFactory stepBuilderFactory) {
        return stepBuilderFactory.get("registrationToXmlStep")
               //设置批的大小1000
                .<Registration, Registration>chunk(1000)
                .reader(registrationToXmlItemReader)
                .writer(multiXmlFileItemWriter)
                .build();
    }

我们设置每个文件的ItemCountLimitPerResource属性时,就要考虑chunk的大小,若每个文件写入的条数小于chunk值时,这时候设置的ItemCountLimitPerResource属性就无效,每个文件的大小就是根据chunk的大小而定了。

所以ItemCountLimitPerResource的值要大于chunk的值,且前者时后者的整数倍

  1. 自定义多文件文件名格式

多文件的文件名是根据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<T>,该组件同原生的MultiResourceItemWriter<T>相比只是修改了文件生成的方法。核心代码如下:

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

 

 


  • 以上内容为实际开发中所总结,本着介绍主要思想思路的原则,仅贴出了核心的代码,如需完整代码或者有不同的见解,敬请在评论和留言以扶正。作者QQ:370731702。

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值