MongoDB在數(shù)據(jù)庫設(shè)計(jì)上和其他關(guān)系數(shù)據(jù)庫有什么不同,估計(jì)第一個(gè)想到的就是自增ID的實(shí)現(xiàn)捕发。Oracle可以通過sequence來實(shí)現(xiàn),mysql和Sqlserver自帶自增id字段扰付。
MongoDB怎么實(shí)現(xiàn)自增id呢?MongoDB官網(wǎng)上也提供了一種實(shí)現(xiàn)的方法颊埃,就是自定義一個(gè)獲取自增ID的方法,然后每次插入的時(shí)候就去獲取下一個(gè)ID,再插入到集合中蝶俱。
下面來講一下基于java的具體實(shí)現(xiàn)班利,原理就是先獲取序列的值,然后設(shè)置給對(duì)應(yīng)的實(shí)體榨呆,代碼如下:
定義序列MongoSequence.java
public class MongoSequence {
@Id
private String id;
private int seq;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getSeq() {
return seq;
}
public void setSeq(int seq) {
this.seq = seq;
}
}
這是簡單的java對(duì)象罗标,就是模擬序列的存儲(chǔ)
序列生成工具類MongoAutoidUtil.java
@Component
public class MongoAutoidUtil {
@Autowired
MongoTemplate mongo;
public int getNextSequence(String collectionName) {
MongoSequence seq = mongo.findAndModify(
query(where("_id").is(collectionName)),
new Update().inc("seq", 1),
options().upsert(true).returnNew(true),
MongoSequence.class);
return seq.getSeq();
}
}
代碼很簡單,就是根據(jù)傳入的序列名稱獲取下一個(gè)序列值积蜻。
通過findAndModify
這個(gè)方法來保證序列唯一闯割,因?yàn)檫@是一個(gè)原子操作。
這段代碼的原理就是竿拆,新建一個(gè)mongoSequence
的Collection(如果沒有才新增)宙拉,然后根據(jù)傳入的collectionName
,根據(jù)_id
即主鍵去找丙笋,如果有值鼓黔,則+1,并返回修改后的值不见,如果沒有則新增一條記錄澳化,并返回該值。
如果改為關(guān)系數(shù)據(jù)庫稳吮,則原理就是這樣缎谷,新建一個(gè)表mongoSequence
,里面兩個(gè)字段_id
,seq
灶似,當(dāng)根據(jù)_id
來取值時(shí)列林,如果沒有記錄,則新增一條記錄酪惭,并返回1希痴,如果有記錄,則把seq
+1春感,并返回修改后的記錄砌创。通過findAndModify
來實(shí)現(xiàn)lock
鎖定這一行的目的。
測(cè)試新增
@Test
public void add() {
for (int i = 0; i < 10; i++) { //增加一條記錄
Article article = new Article();
article.setId(mongoAutoidUtil.getNextSequence("seq_article"));
article.setTitle("MongoTemplate的基本使用");
article.setAuthor("kcy");
article.setUrl("http://jianshu.com/");
article.setTags(Arrays.asList("java", "mongodb", "spring"));
article.setVisitCount(0L);
article.setAddTime(new Date());
mongoTemplate.save(article);
}
Iterable<Article> articles = articleRepository.findAll();
articles.forEach(article2 -> {
System.out.println(article2.toString());
});
}
在設(shè)置article的id時(shí)通過article.setId(mongoAutoidUtil.getNextSequence("seq_article"));
來獲取序列的值鲫懒,并賦給這個(gè)id嫩实。
自增id的實(shí)現(xiàn)和oracle的序列原理基本一致。
源碼下載
[本工程詳細(xì)源碼]
(https://github.com/chykong/java_component/tree/master/chapter4_3_mongodb_autoid)