我们看名字大概也能猜到这个原子性操作是用来做什么的,查找和更新。
一、我们的业务场景
我们为了业务需求,需要在分类表中增加一个int类型的不重复的id。
二、方案思考
当初想的是比较low的方法,根据id排序查出所有的数据,然后将最大的id取出+1,然后在插入一条。单节点服务感觉没啥问题,但是一旦节点数增加,不能保证id不重复。如果加表级锁,可能会有性能问题。
三、解决方案
通过看文章发现 mongodb 有一个原子操作方法叫findAnModifyd,它可以指定某个键进行增长一定的值并获取此值,插入和更新是同步操作。
四、具体实现
我用的是spring boot框架
首先我们创建一个用来存放自增id的表叫collectionIncId,两个属性,一个是自增id,一个是表名( colention名字 ),这样我们可以在一个表维护多个需要自增id表的自增id。
要增加的是classType表中的id,从上面图中我们看到classType表中的id初始值是3,这个可以随便定。所以下面表中会从3开始增加
接下来看代码实现
首先在model定义一个collectionIncId的一个映射model,目录结构及内容如下
package com.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @Auther: Xu
* @Date: 2021/4/12 - 04 - 12 - 15:55
* @Description: com.model
* @version: 1.0
*/
@Data
@Document(collection = "collectionIncId")
public class CollectionIncId {
@Id
private String _id;
private int id;
private String collName;
}
然后在我们操作classType这张表的service中定义方法
/**
* @Auther: Xu
* @Date: 2021/4/9 - 04 - 09 - 16:56
* @Description: com.dao.classTypedao
* @version: 1.0
*/
@Service
public class ClassTypeService {
@Autowired
private ClassTypedao classTypedao;
@Autowired
private MongoTemplate mongoTemplate;
public void insertOne(ClassTypeModel classTypeModel){
classTypedao.save(classTypeModel);
}
/**
* 根据_id删除一条数据
*/
public void deleteOne(String id){
classTypedao.delete(id);
}
/**
* 获取自增id
* @param collectionName 获取哪张表的自增id
* @return
*/
public int getNextSequence(String collectionName) {
FindAndModifyOptions options = new FindAndModifyOptions();
// 先查询,如果没有符合条件的,会执行插入,插入的值是查询值 + 更新值
options.upsert(true);
// 返回当前最新值
options.returnNew(true);
Update update = new Update();
//inc对应的是原生$inc
update.inc("id", 1);
//collName是自增id表中的表名的Key
CollectionIncId collect = mongoTemplate.findAndModify(
query(where("collName").is(collectionName)),
update,
options,
CollectionIncId.class
);
return collect.getId();
}
}
collName是collectionIncId中的key
接下来在classType 的 controller 中使用这个方法
@RestController
public class ClassTypeTools {
@Autowired
private ClassTypeService classTypeService;
@GetMapping(value = "/createClass")
public RespData createClass(@RequestParam(required = true) String label) throws Exception{
RespData respData = new RespData(RespCode.SUCCESS);
//调取获取自增id的方法 获取id
int i = classTypeService.getNextSequence("classType");
System.out.println("最后一个id"+i);
ClassTypeModel classTypeModel = new ClassTypeModel();
classTypeModel.setId(i);
classTypeModel.setLabel(label);
//插入
classTypeService.insertOne(classTypeModel);
return respData;
}
}
OK,这样就实现了