Java中如何防止POJO类字段存入MongoDB时出现重复值
解决方案
原代码问题分析
- 未查询数据库校验重复:判断重复的逻辑基于本地新建的
ArrayList,仅包含当前传入的itemName,永远不会命中重复判断,完全没有查询MongoDB中已存在的记录 - 数据存储逻辑错误:调用
mongoTemplate.save()时传入的是List对象而非Items实体对象,存储对象类型不符合预期 - 循环逻辑完全冗余:创建的集合只有1个元素,循环遍历没有任何实际作用
修复步骤
步骤1:为itemName字段添加唯一索引(数据库层兜底防重)
这一步是最可靠的防重手段,即使应用层校验出现并发漏判,数据库也会直接拒绝重复写入。
首先修改POJO类,给itemName加唯一索引注解:
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "items") // 显式指定集合名,可选但推荐 public class Items { @Id private String id; @Indexed(unique = true) // 新增唯一索引注解 private String itemName; // 此处省略getter、setter方法 }
然后开启Spring Data MongoDB的自动索引创建,在application.yml/application.properties添加配置:
spring.data.mongodb.auto-index-creation=true
如果不想开启自动索引创建,也可以手动调用接口创建索引,项目启动时执行一次即可:
mongoTemplate.indexOps(Items.class).ensureIndex(new Index("itemName", Sort.Direction.ASC).unique());
步骤2:修复业务层写入逻辑
先查询数据库是否存在相同itemName的记录,存在则直接抛出指定错误,不存在再执行插入,同时捕获唯一索引冲突异常处理并发场景:
import org.springframework.dao.DuplicateKeyException; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; public void addCategory(Items item) { // 1. 先查询数据库判断是否已存在相同itemName boolean exists = mongoTemplate.exists( Query.query(Criteria.where("itemName").is(item.getItemName())), Items.class ); if (exists) { throw new IllegalArgumentException("item already exists"); } try { // 2. 不存在则执行插入 mongoTemplate.save(item); } catch (DuplicateKeyException e) { // 并发请求场景下,两个请求同时通过前面的exists校验时,会触发数据库唯一索引冲突,统一转成指定错误 throw new IllegalArgumentException("item already exists"); } }
内容的提问来源于stack exchange,提问作者Sahith Manchi
相关产品推荐
相关产品推荐

