使用 Spring 批处理读取文件并写入 Map
Using Spring batch to read a file and write to a Map
背景
我是 Spring 批处理的新手,有以下要求:
- 读取最少包含一百万条记录的文件(CSV、竖线分隔等)
- 将文件中的每一行加载到 Map 中,键作为第一列,值作为域 object/POJO。
我知道 Spring 批处理有一些称为面向块的处理,其中配置 reader、处理器和编写器来处理由提交间隔管理的一定数量的记录。这可以使用 reader 的任务执行器或通过分区添加另一层多线程来进一步扩展。
问题
如上面第 2 点所述,我想将我的文件加载到地图中。为了便于讨论,假设我实现了以下 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 来获取我的文件中记录的聚合映射;但是,在 ItemWriter 中保存这样的 Map 并不是解决此问题的最佳方法。另一个问题是使用 ConcurrentHashMap 可能会降低性能,但我看不到任何其他方法可以以线程安全的方式将文件聚合到 Map 中。
有没有更好的方法将我的文件聚合到一个 Map 中,而不是在我的 writer 中保存一个 Map 并使用 ConcurrentHashMap?
差不多就是这样。您可以进行一些小的改进,例如将地图放在一个单独的 bean 中,这将允许您为编写器 bean 和地图提供不同的生命周期,并将地图的读取器与编写器分离。例如,您可以将地图放在一个作业范围的 bean 中,并且仍然让编写器成为一个单身人士。
如果您的作业被划分为多个线程,您只需要 ConcurrentHashMap
(我假设您不希望跨作业共享地图)。
为什么不使用 File Item Writer。
我假设这张地图应该写入一个文件。可能是一个平面文件 (txt)
如果是这种情况,请尝试使用 FlatFileItemWriter . In case you need to write this data to a xml file , you can use StaxEventItemWriter。
即使您不需要将数据写入文件(只需要批处理结束时的地图)。我认为将数据写入文件然后从文件中读取整个地图将是 "cheaper"。将映射保存在作业范围内意味着该对象将在每个块中持久保存在数据库中,并将在每个块上从数据库中检索,这是非常昂贵的操作。
背景
我是 Spring 批处理的新手,有以下要求:
- 读取最少包含一百万条记录的文件(CSV、竖线分隔等)
- 将文件中的每一行加载到 Map 中,键作为第一列,值作为域 object/POJO。
我知道 Spring 批处理有一些称为面向块的处理,其中配置 reader、处理器和编写器来处理由提交间隔管理的一定数量的记录。这可以使用 reader 的任务执行器或通过分区添加另一层多线程来进一步扩展。
问题
如上面第 2 点所述,我想将我的文件加载到地图中。为了便于讨论,假设我实现了以下 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 来获取我的文件中记录的聚合映射;但是,在 ItemWriter 中保存这样的 Map 并不是解决此问题的最佳方法。另一个问题是使用 ConcurrentHashMap 可能会降低性能,但我看不到任何其他方法可以以线程安全的方式将文件聚合到 Map 中。
有没有更好的方法将我的文件聚合到一个 Map 中,而不是在我的 writer 中保存一个 Map 并使用 ConcurrentHashMap?
差不多就是这样。您可以进行一些小的改进,例如将地图放在一个单独的 bean 中,这将允许您为编写器 bean 和地图提供不同的生命周期,并将地图的读取器与编写器分离。例如,您可以将地图放在一个作业范围的 bean 中,并且仍然让编写器成为一个单身人士。
如果您的作业被划分为多个线程,您只需要 ConcurrentHashMap
(我假设您不希望跨作业共享地图)。
为什么不使用 File Item Writer。
我假设这张地图应该写入一个文件。可能是一个平面文件 (txt)
如果是这种情况,请尝试使用 FlatFileItemWriter . In case you need to write this data to a xml file , you can use StaxEventItemWriter。
即使您不需要将数据写入文件(只需要批处理结束时的地图)。我认为将数据写入文件然后从文件中读取整个地图将是 "cheaper"。将映射保存在作业范围内意味着该对象将在每个块中持久保存在数据库中,并将在每个块上从数据库中检索,这是非常昂贵的操作。