SpringBoot+mongoDB實現id自增
阿新 • • 發佈:2019-02-08
ets pac beans http etc current 不用 inf ppi
這段時間給朋友做了一個微信小程序,順便練習一下spring boot,雖然項目使用的是JPA+MySQL,但是好奇嘗試了一下MongoDB實現自增ID,雖然MongoDB很少有自增ID的需求(在分布式環境中,多個機器同步一個自增ID不但費時且費力,MongoDB從一開始就是設計用來做分布式數據庫的,處理多個節點是一個核心要求,而ObjectId在分片環境中要容易生成的多),但是需求是多變的,難免會遇到需要自增的需求。
MongoDB有默認的ObjectId,是一個12字節的 BSON 類型字符串。按照字節順序,依次次代表:
- 4字節:UNIX時間戳
- 3字節:表示運行MongoDB的機器
- 2字節:表示生成此_id的進程
- 3字節:由一個隨機數開始的計數器生成的值
Spring boot中可以使用MongoTemplate操作MongoDB,但是不能自增ID,只能手動實現:
1).自定義註解用於標識需要自增的Field.
package com.example.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoIncKey {}
2).創建數據表存儲當前的id號
id的自增進度需要一個數據表存儲(只是存儲當前id號數據,可以不用數據庫而用其他形式)
@Document(collection = "inc")
public class IncInfo {
@Id
private String id;// 主鍵
@Field
private String collName;// 需要自增id的集合名稱(這裏設置為MyDomain)
@Field
private Integer incId;// 當前自增id值
// 省略getter、setter
3).實現監聽類
監聽器用於監聽Mongo Event,該類繼承AbstractMongoEventListener類,因為我們需要在JAVA對象轉換成數據庫對象的時候操作id字段實現id自增,所以覆蓋onBeforeConvert方法(詳見spring-data文檔,https://docs.spring.io/spring-data/data-document/docs/current/reference/html/,5.11節)
package com.example.listener;
import java.lang.reflect.Field;
import com.example.annotation.AutoIncKey;
import com.example.domain.MyDomain;
import com.example.domain.IncInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
@Component
public class SaveEventListener extends AbstractMongoEventListener<Object>{
private static final Logger logger= LoggerFactory.getLogger(SaveEventListener.class);
@Autowired
private MongoTemplate mongo;
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
logger.info(event.getSource().toString());
MyDomain source=(MyDomain)event.getSource();
if (source != null) {
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
// 如果字段添加了我們自定義的AutoIncKey註解
if (field.isAnnotationPresent(AutoIncKey.class)) {
// 設置自增ID
field.set(source, getNextId(source.getClass().getSimpleName()));
}
}
});
}
}
private Integer getNextId(String collName) {
Query query = new Query(Criteria.where("collName").is(collName));
Update update = new Update();
update.inc("incId", 1);
FindAndModifyOptions options = new FindAndModifyOptions();
options.upsert(true);
options.returnNew(true);
IncInfo inc= mongo.findAndModify(query, update, options, IncInfo.class);
return inc.getIncId();
}
}
4).在我們的對象中id字段上添加註解
@Id
@AutoIncKey
private Integer id=0;
至此就實現了Mongodb的自增id。
SpringBoot+mongoDB實現id自增