代码之家  ›  专栏  ›  技术社区  ›  Chetan Kinger

使用Spring批处理读取文件并写入Map

  •  1
  • Chetan Kinger  · 技术社区  · 9 年前

    出身背景

    我对Spring batch相当陌生,有以下要求:

    1. 读取一个最少有百万条记录的文件(CSV、管道分隔等)
    2. 将文件中的每一行加载到Map中,键作为第一列,值作为域对象/POJO。

    我理解Spring批处理有一种称为面向块的处理,其中配置一个读取器、处理器和写入器来处理由提交间隔控制的特定数量的记录。这可以通过使用阅读器的任务执行器或通过分区添加另一层多线程来进一步扩展。

    问题

    如上文第2点所述,我想将文件加载到Map中。为了便于讨论,假设我实现了下面的ItemWriter,它将块聚合到Map中。

    public class MapItemWriter implements ItemWriter<SomePOJO> {
    
        private Map<String, SomePOJO> somePojoMap; 
    
        public MapItemWriter() {
            System.out.println("Writer created ");
            somePojoMap= new ConcurrentHashMap<String, SomePOJO>();
        }
    
        public void write(List<? extends SomePOJO> item) throws Exception {
            if (item != null && item.size() > 0) {
                for (SomePOJO data : item) {
                    String uniqueId = data.Id();
                    somePojoMap.put(uniqueId, data);
                 }
            }
        }
    
        public Map<String, SomePojo> getSomePojoMap() {
            return somePojoMap;
        }
    }
    

    由于我可以访问我的ItemWriter bean,我可以稍后调用getSomePojoMap来获取文件中记录的聚合Map;然而,在ItemWriter中持有这样的Map并不是最好的方式。另一个问题是,使用ConcurrentHashMap可能会降低性能,但我看不到任何其他方法可以以线程安全的方式将文件聚合到Map中。

    有没有更好的方法将我的文件聚合成Map,而不是在我的编写器中保存Map并使用ConcurrentHashMap?

    2 回复  |  直到 9 年前
        1
  •  1
  •   Artefacto    9 年前

    差不多就是这样。您可以做一些小的改进,比如将地图放在一个单独的bean中,这将允许您为writer bean和地图拥有不同的生命周期,并将地图的读者与writer分离。例如,您可以将映射放在一个作业范围的bean中,而编写器仍然是一个单例。

    你只需要一个 ConcurrentHashMap 如果您的作业被划分为多个线程(我假设您不希望在作业之间共享映射)。

        2
  •  0
  •   Hezi Schrager    9 年前

    为什么不使用文件项编写器。

    我认为这张地图应该写入一个文件。可能是平面文件(txt)

    如果是这种情况,尝试使用 FlatFileItemWriter 。如果需要将此数据写入xml文件,可以使用 StaxEventItemWriter .

    即使您不需要将数据写入文件(在批处理结束时只需要映射)。我认为将数据写入文件,然后从文件中读取整个地图会“更便宜”。在作业范围内保存映射意味着该对象将在每个块的数据库中持久化,并且将在每个区块的数据库中检索,这是一项非常昂贵的操作。