如何使用MongoItemWriter写入List<T>?自定义实现遇类型转换错误
Spring Batch处理器返回列表时MongoItemWriter的错误解决
我的Spring Batch处理器返回List<Object>,需要将列表中的对象批量写入MongoDB,但自定义MongoItemWriter处理列表时遇到两个错误:
- 错误1:
class org.bson.Document cannot be cast to class java.util.Collection (org.bson.Document is in unnamed module of loader 'app'; java.util.Collection is in module java.base of loader 'bootstrap') - 错误2:
Attempt to update step execution id=1 with wrong version (1), where current version is 2
相关代码
处理器代码
@Override public List<PEntity> process(PSEntity item) { log.trace("Traitement d'une entrée PSEntity: {}", item); List<PL> r = this.r.findRP(item.getP()); if (r.isEmpty()) { return null; } for (PL r : r) { r.setRr(true); r.setHr(LocalDateTime.now()); } List<PLEntity> pLEntities = r.stream().map(this.pDM::ppDMEntity).toList(); return pLEntities; }
自定义RMongoWriter代码
public class RMongoWriter<T> extends MongoItemWriter<List<T>> { private MongoOperations template; private MongoItemWriter<T> delegate; @Override public void write(final List<? extends List<T>> lists) throws Exception { for (final List<T> list : lists) { delegate.write(list); } } @Bean public MongoItemWriter<List<PLEntity>> writer(MongoTemplate mongoTemplate, BatchConfigurationProperties batchConfigurationProperties) { MongoItemWriter<List<PlaqueLueEntity>> writer = new MongoItemWriter<>(); writer.setTemplate(mongoTemplate); writer.setCollection(String.valueOf(CollectionEnum.COLLECTION.PL)); return writer; } }
BatchConfiguration配置
@Bean public MongoItemWriter<List<PLEntity>> rWriter() { return new RMongoWriter().writer(mongoTemplate, batchConfigurationProperties); }
错误原因分析
错误1原因
继承MongoItemWriter<List<T>>的做法有误:MongoItemWriter原本设计用于处理单个实体对象,它会尝试把传入的List<T>当作单个Mongo文档序列化,在内部转换为Document时,因List不是Mongo实体类,触发类型转换异常。
错误2原因
这是Spring Batch步骤执行的版本冲突问题,根源是第一个错误导致步骤执行异常,Spring Batch更新步骤状态时,异常引发的重复更新或事务回滚导致版本不匹配。
解决方案
无需继承MongoItemWriter,直接实现ItemWriter<List<T>>,内部用标准MongoItemWriter<T>处理列表中的每个实体:
修改后的自定义Writer
import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.data.MongoItemWriter; import org.springframework.data.mongodb.core.MongoTemplate; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; public class RMongoWriter<T> implements ItemWriter<List<T>> { private final MongoItemWriter<T> delegate; public RMongoWriter(MongoItemWriter<T> delegate) { this.delegate = delegate; } @Override public void write(List<? extends List<T>> items) throws Exception { // 展开所有列表中的实体,统一批量写入 List<T> allEntities = items.stream() .filter(Objects::nonNull) .flatMap(List::stream) .collect(Collectors.toList()); if (!allEntities.isEmpty()) { delegate.write(allEntities); } } // 单独定义MongoItemWriter的Bean,与自定义Writer解耦 @Bean public MongoItemWriter<PLEntity> mongoPLEntityWriter(MongoTemplate mongoTemplate) { MongoItemWriter<PLEntity> writer = new MongoItemWriter<>(); writer.setTemplate(mongoTemplate); writer.setCollection(String.valueOf(CollectionEnum.COLLECTION.PL)); return writer; } }
修改BatchConfiguration配置
@Bean public ItemWriter<List<PLEntity>> rWriter(MongoItemWriter<PLEntity> mongoPLEntityWriter) { return new RMongoWriter<>(mongoPLEntityWriter); }
额外注意
- 处理器返回
null时,Spring Batch会自动跳过该项,需确保此逻辑符合业务预期。 - 若需优化写入性能,可调整Spring Batch的chunk大小,配合MongoDB的批量插入机制提升效率。
内容的提问来源于stack exchange,提问作者jenoh
相关产品推荐
相关产品推荐

