pom
因為項目中采用Morphia
(MongoDB
的ODM
框架,對象-文檔映射(object-document mapper
)),因此需要在pom
文件中引入相應依賴:
<dependency>
<groupId>dev.morphia.morphia</groupId>
<artifactId>core</artifactId>
<version>1.5.3</version>
</dependency>
因為Morphia
依賴於mongo-java-driver
,因此無需在pom
文件中繼續導入mongo-java-driver
.
配置
(1) 配置文件
application.yaml
中配置如下所示:
data:
mongodb:
database: {數據庫名稱}
uri: mongodb://{用戶名}:{密碼}@{服務器地址}:27017/{數據庫名稱}
上述配置中,
{}
包圍的地方請按照各自項目實際情況填寫.
(2) 代碼配置
@Data
@Configuration
public class MorphiaConfig {
private MongoClient mongoClient;
/**
* 設置連接最大空閑時間(到達時間,連接關閉)
* @return mongo client屬性
*/
@Bean
public MongoClientOptions mongoClientOptions() {
return MongoClientOptions.builder()
.maxConnectionIdleTime(6000 * 5)
.maxConnectionLifeTime(0)
.build();
}
@Autowired
public MorphiaConfig(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
@Bean
public Datastore datastore(@Autowired MongoClient mongoClient) {
Morphia res = new Morphia();
// 確定Mongo實體類的存放包名
res.mapPackage("com.test.log.entity");
Datastore datastore = res.createDatastore(mongoClient, "ops");
// 為實體類創建索引
datastore.ensureIndexes();
return datastore;
}
}
代碼中無需自行配置MongoClient
(Spring boot
會自動完成MongoClient
的初始化),當然也允許自行設置Mongo
的連接參數.
實體類
項目中需要存放日志,並且通過MongoDB
的TTL
特性設置過期時間,以便通過MongoDB
完成日志刪除任務.
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
// 必須添加,以便Morphia識別此類為`MongoDB`的實體類,`logInfo`是表名
@Entity(value = "logInfo", noClassnameStored = true)
@Indexes({
// expireTime存放日志過期時間,創建TTL index
@Index(fields = @Field(value = "expireTime"), options = @IndexOptions(expireAfterSeconds = 0)),
// 創建復合索引
@Index(fields = {@Field("deviceId"), @Field("module"), @Field(value = "time", type = DESC)}),
@Index(fields = {@Field("deviceId"), @Field(value = "time", type = DESC)})
})
public class LogInfo {
@Id
private ObjectId id;
private Date time;
@JsonIgnore
private Date expireTime;
private String module;
private String level;
private String deviceId;
private String msg;
}
日志的存放和讀取是在不同的項目完成,在查詢MongoDB
時遇到反序列化問題,異常如下所示:
WARN dev.morphia.mapping.DefaultCreator - Class not found defined in dbObj:
查詢源碼分析,是因為Morphia
在存儲數據的時候,會將實體類
的名稱
存入數據庫中.
查詢時Morphia
根據類名
查找相應的實體類
並進行反序列化
.
因為不同的項目中,實體類的包名不一致導致出現以上錯誤.
解決方案比較簡單,通過注解告知Morphia
存儲數據時不要存儲包名即可,具體如下所示:
`@Entity(value = "logInfo", noClassnameStored = true)`.
CRUD
操作
(1) 存儲操作
LogInfo logInfo = LogInfo.builder()
.time(dateTime)
.expireTime(dateExpireTime)
.level(level)
.module(module)
.deviceId(deviceId)
.msg(msg)
.build();
try {
//插入日志到mongoDB
datastore.save(logInfo);
} catch (RuntimeException e) {
log.error(AppStatus.IDB_WRITE_FAIL.getError(), e);
}
(2) 查詢操作
final Query<LogInfo> query = datastore.createQuery(LogInfo.class).filter("deviceId = ", request.getDeviceId());
// 列表查詢
if (!CollectionUtils.isEmpty(request.getModules())) {
query.filter("module in ", request.getModules().toArray());
}
// 根據時間查詢,使用filter就不太恰當了
if (null != request.getStartTime()) {
query.field("time").greaterThanOrEq(request.getStartTime());
}
if (null != request.getFinishTime()) {
query.field("time").lessThanOrEq(request.getFinishTime());
}
// 查詢記錄總數
int count = query.count());
// 設置排序規則,查詢具體數據
query.order(Sort.descending("time"));
// 獲取數據游標
MongoCursor<LogInfo> logInfoMongoCursor = query.find(
new FindOptions()
.skip((request.getPageNum() - 1) * request.getPageSize())
.limit(request.getPageSize())
);
// 通過數據游標,逐個獲取數據記錄
while (logInfoMongoCursor.hasNext()) {
logInfoPage.add(logInfoMongoCursor.next());
}
刪除以及更新操作就不再贅述,
Morphia
接口比較明晰,容易入門.
PS:
如果您覺得我的文章對您有幫助,請關注我的微信公眾號,謝謝!