MongoDB在數(shù)據(jù)庫(kù)設(shè)計(jì)上和其他關(guān)系數(shù)據(jù)庫(kù)有什么不同,估計(jì)第一個(gè)想到的就是自增ID的實(shí)現(xiàn)。Oracle可以通過(guò)sequence來(lái)實(shí)現(xiàn),mysql和Sqlserver自帶自增id字段。
MongoDB怎么實(shí)現(xiàn)自增id呢?MongoDB官網(wǎng)上也提供了一種實(shí)現(xiàn)的方法,就是自定義一個(gè)獲取自增ID的方法,然后每次插入的時(shí)候就去獲取下一個(gè)ID,再插入到集合中。
下面來(lái)講一下基于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;
}
}
這是簡(jiǎn)單的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();
}
}
代碼很簡(jiǎn)單,就是根據(jù)傳入的序列名稱獲取下一個(gè)序列值。
通過(guò)findAndModify這個(gè)方法來(lái)保證序列唯一,因?yàn)檫@是一個(gè)原子操作。
這段代碼的原理就是,新建一個(gè)mongoSequence的Collection(如果沒(méi)有才新增),然后根據(jù)傳入的collectionName,根據(jù)_id即主鍵去找,如果有值,則+1,并返回修改后的值,如果沒(méi)有則新增一條記錄,并返回該值。
如果改為關(guān)系數(shù)據(jù)庫(kù),則原理就是這樣,新建一個(gè)表mongoSequence,里面兩個(gè)字段_id,seq,當(dāng)根據(jù)_id來(lái)取值時(shí),如果沒(méi)有記錄,則新增一條記錄,并返回1,如果有記錄,則把seq+1,并返回修改后的記錄。通過(guò)findAndModify來(lái)實(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í)通過(guò)article.setId(mongoAutoidUtil.getNextSequence("seq_article"));來(lái)獲取序列的值,并賦給這個(gè)id。
自增id的實(shí)現(xiàn)和oracle的序列原理基本一致。
源碼下載
[本工程詳細(xì)源碼]
(https://github.com/chykong/java_component/tree/master/chapter4_3_mongodb_autoid)