新增一条知识文档数据时,希望文档名称是唯一的,因此在业务逻辑中做了校验:
public Doc addDoc(Doc doc, SetattachmentIds, Set imageIds) { // 判断文档名称是否已存在 validateDocName(doc.getName()); // 保存文档 doc = knowledgeMongoTemplate.save(doc); return doc; } private void validateDocName(String name) { Optional docOptional = Optional.ofNullable( knowledgeMongoTemplate.findOne(new Query(Criteria.where("name").is(name)), Doc.class) ); if (docOptional.isPresent()) { throw new CommonException(BizCodeEnum.DOC_NAME_EXIST); } }
但是这种做法会引发一个问题,就是当有多个线程同时执行这个接口时,同时根据名称name判断数据库中有没有这条数据,发现没有,两个线程都向文档中添加了这条数据,name此时数据库中的name就不是唯一的了,因此需要创建唯一性索引。
2、问题复现:一开始我使用了@Indexed(unique=true)这个注解,但是奈何这个注解不生效,因为Spring Data MongoDB3.X 后的版本不再支持自动创建索引,如果要坚持使用@Indexed注解需要额外的设置,并建议我们在手动创建索引。看了网上说的加一个配置:
spring.data.mongodb.auto-index-creation = true
但是注解还是不生效,于是选择了手动创建索引。
3、解决方案:@Configuration
public class MongoDbConfig {
final MongoTemplate knowledgeTemplate;
public MongoDbConfig(MongoTemplate mongoTemplate) {
this.knowledgeTemplate = mongoTemplate;
}
@EventListener(ApplicationReadyEvent.class)
public void initIndicesAfterStartup() {
// Doc是实体类,给Doc集合中的name字段加索引,并且是唯一索引
knowledgeTemplate.indexOps(Doc.class).ensureIndex(new Index().on("name", Sort.Direction.ASC).unique());
}
}



