1 場(chǎng)景
spring集成mongo后政冻,可以使用mongoTemplate
進(jìn)行mongo操作。
1.1 當(dāng)前問(wèn)題
mongoTemplate寫(xiě)入或者更新數(shù)據(jù)庫(kù)時(shí)贼陶,操作對(duì)象
可以是Java bean實(shí)體類(lèi)
也可以是Map對(duì)象
卖宠。
<T> T insert(T objectToSave);
<T> T insert(T objectToSave, String collectionName);
例子如下:
- 使用map作為存儲(chǔ)對(duì)象
Map<String,Object> map=new HashMap<>();
map.put("userName","張三");
//年齡為字符串:18歲
map.put("age","18歲");
mongoTemplate.insert(map,"t_user_info");
Map<String,Object> map1=new HashMap<>();
map1.put("userName","張三");
//年齡為數(shù)字:18
map1.put("age",18);
mongoTemplate.insert(map1,"t_user_info");
- 使用java對(duì)象作為存儲(chǔ)對(duì)象
@Data
public class UserInfo{
private String userName;
private Integer age;
}
UserInfo userInfo=new UserInfo();
userInfo.setUserName("張三");
//年齡為數(shù)字:18
userInfo.setAge(18);
mongoTemplate.insert(userInfo,"t_user_info");
因?yàn)閙ongo中,同一個(gè)表
中二打,同一個(gè)字段
,不同數(shù)據(jù)
的字段類(lèi)型
可以不一樣掂榔。即如上示例继效,使用map作為存儲(chǔ)對(duì)象,不同的記錄衅疙,字段age類(lèi)型莲趣,既可以是字符類(lèi)型
“18歲”鸳慈,也可以是數(shù)字類(lèi)型
18饱溢,數(shù)據(jù)庫(kù)中數(shù)據(jù)格式如下:
/* 1 */
{
"_id" : ObjectId("5f8107c5f34b265ecada41ff"),
"userName" : "張三",
"age" : "18歲"
}
/* 2 */
{
"_id" : ObjectId("5f8107c5f34b265ecada4200"),
"userName" : "張三",
"age" : 18
}
如只使用java中的bean對(duì)象
作為存儲(chǔ)對(duì)象,則同一個(gè)表中所有的數(shù)據(jù)的數(shù)據(jù)類(lèi)型均一致
走芋,如下:
/* 1 */
{
"_id" : ObjectId("5f8107c5f34b265ecada4211"),
"userName" : "張三",
"age" : 18
}
1.2 選型
java中使用map
和自定義bean
都可以作為mongo的存儲(chǔ)對(duì)象绩郎。我們對(duì)這兩種方式進(jìn)行對(duì)比:
1.2.1 map作為存儲(chǔ)對(duì)象
- 優(yōu)點(diǎn)
(1)代碼簡(jiǎn)單,定義map即可存儲(chǔ)對(duì)象
(2)不用為每個(gè)專(zhuān)門(mén)的表定義java對(duì)象
- 缺點(diǎn)
(1)每次操作數(shù)據(jù)時(shí)翁逞,手動(dòng)定義map的鍵值肋杖。手寫(xiě)代碼,容易寫(xiě)錯(cuò)
挖函。字段名容易出錯(cuò)状植,導(dǎo)致名稱(chēng)相似
的字段出現(xiàn);字段值的類(lèi)型
容易出錯(cuò)怨喘,導(dǎo)致一個(gè)同一個(gè)字段不同數(shù)據(jù)的字段類(lèi)型不一致
津畸,此問(wèn)題是非常致命的。
(2)mongo增加字段必怜,無(wú)需更改表結(jié)構(gòu)肉拓。需額外維護(hù)mongo表結(jié)構(gòu)說(shuō)明文檔
,人工通過(guò)文檔定義字段的名稱(chēng)梳庆、含義和類(lèi)型
暖途。
(3)mongo中增加字段無(wú)需更改表結(jié)構(gòu),不需要DBA授權(quán)膏执,對(duì)mongo字段如果無(wú)限制驻售,如果管理不善,容易出現(xiàn)字段的數(shù)量暴增
更米。
(4)需要人工定義表名稱(chēng)的常量集合欺栗。
1.2.1 自定義bean作為存儲(chǔ)對(duì)象
- 優(yōu)點(diǎn)
(1)通過(guò)mongo表的映射java對(duì)象,可以清晰知道m(xù)ongo表的表結(jié)構(gòu)
(字段名稱(chēng)、字段類(lèi)型纸巷、表名稱(chēng))
(2)不需要人工定義表名稱(chēng)的常量集合镇草。映射對(duì)象上通過(guò)注解
或者默認(rèn)名稱(chēng)
,可以自動(dòng)獲取mongo表的名稱(chēng)瘤旨。
- 缺點(diǎn)
(1)需要手動(dòng)為每個(gè)表建立專(zhuān)門(mén)的java對(duì)象
(2)原始的mongoTemplate中api接口無(wú)法限制
所有的操作必須使用java對(duì)象進(jìn)行操作梯啤。需要人工進(jìn)行接口的二次封裝
(且只能使用封裝的接口)。
經(jīng)過(guò)對(duì)比存哲,我們選擇使用自定義bean
作為存儲(chǔ)對(duì)象因宇。
2 版本
springBoot:2.2.9.RELEASE
mongodb:4.0
3 步驟
3.1 基礎(chǔ)代碼
(1)定義java bean的父類(lèi)
import lombok.Data;
import java.io.Serializable;
/**
* mongo的bean定義
* <br>實(shí)現(xiàn)此接口的類(lèi),可以進(jìn)行mongo數(shù)據(jù)庫(kù)操作
**/
@Data
public class MongoBean implements Serializable {
/**
* mongo主鍵(對(duì)應(yīng)數(shù)據(jù)庫(kù)中自動(dòng)生成的字段:_id)
* 此字段不可設(shè)置(mongo自己生成)
*/
private String id;
/**
* 刪除標(biāo)志(false:正常祟偷;true:刪除)
*/
private Boolean delFlag;
/**
* 創(chuàng)建人ID
*/
private String createUserId;
/**
* 創(chuàng)建人姓名
*/
private String createUserName;
/**
* 創(chuàng)建時(shí)間
*/
private Integer createDate;
/**
* 更新人ID
*/
private String updateUserId;
/**
* 更新人姓名
*/
private String updateUserName;
/**
* 更新時(shí)間
*/
private Integer updateDate;
}
所有的mongo表映射的java對(duì)象察滑,均需繼承此父類(lèi)。
如下:
import org.springframework.data.mongodb.core.mapping.Document;
/**
* 用戶(hù)表
*/
@Document("t_user_info")
public class TUserInfo extends MongoBean {
/**
* 用戶(hù)名
*/
private String userName;
/**
* 年齡
*/
private Integer age;
}
(2)定義mongo游標(biāo)執(zhí)行器
/**
* mongo游標(biāo)執(zhí)行器
**/
public interface Executor<T> {
/**
* 執(zhí)行
* @param cModel 執(zhí)行實(shí)體類(lèi)
* @return void
*/
void invoke(T cModel) throws Exception;
}
3.2 部分API封裝
3.2.1 插入數(shù)據(jù)
/**
* 插入數(shù)據(jù)
* @param objectToSave
* @return T
*/
public <T extends MongoBean> T insert(T objectToSave){
return mongoTemplate.insert(objectToSave);
}
/**
* 批量插入數(shù)據(jù)
* @param batchToSave
* @return java.util.Collection<T>
*/
public <T extends MongoBean> Collection<T> insertAll(Collection<? extends T> batchToSave){
return mongoTemplate.insertAll(batchToSave);
}
3.2.2 條件刪除
/**
* 條件刪除
* @param query
* @param entityClass
* @return
*/
public <T extends MongoBean> DeleteResult remove(Query query, Class<T> entityClass){
return mongoTemplate.remove(query,entityClass);
}
3.2.3 查詢(xún)數(shù)據(jù)
/**
* 查詢(xún)滿(mǎn)足條件記錄
* @param query
* @param entityClass
* @return java.util.List<T>
*/
public <T extends MongoBean> List<T> find(Query query, Class<T> entityClass){
return mongoTemplate.find(query,entityClass);
}
/**
* 查詢(xún)第一條
* @param query
* @param entityClass
* @return T
*/
public <T extends MongoBean> T findOne(Query query, Class<T> entityClass){
return mongoTemplate.findOne(query,entityClass);
}
/**
* 根據(jù)主鍵查詢(xún)
* @param id
* @param entityClass
* @return T
*/
public <T extends MongoBean> T findById(Object id, Class<T> entityClass){
return mongoTemplate.findById(id,entityClass);
}
/**
* 查詢(xún)總數(shù)
* @param query
* @param entityClass
* @return long
*/
public <T extends MongoBean> long count(Query query, Class<T> entityClass){
return mongoTemplate.count(query,entityClass);
}
3.2.4 更新數(shù)據(jù)
/**
* 更新第一條
* @param query 查詢(xún)條件
* @param mongoBean 要更新的實(shí)體
* @param updateFields
* @return com.mongodb.client.result.UpdateResult
*/
public <T extends MongoBean> UpdateResult extUpdateFirst(Query query, T mongoBean,String... updateFields) throws Exception{
Update update=getUpdateFromBean(mongoBean,updateFields);
return mongoTemplate.updateFirst(query,update,mongoBean.getClass());
}
/**
* 批量更新
* @param query 查詢(xún)條件
* @param mongoBean 要更新的實(shí)體
* @param updateFields 要更新的字段(有參數(shù)時(shí)修肠,更新指定的字段贺辰;無(wú)此參數(shù)時(shí),更新mongoBean所有不為空的字段)
* @return com.mongodb.client.result.UpdateResult
*/
public <T extends MongoBean> UpdateResult extUpdateMulti(Query query, T mongoBean,String... updateFields) throws Exception{
Update update=getUpdateFromBean(mongoBean,updateFields);
return mongoTemplate.updateMulti(query,update,mongoBean.getClass());
}
3.2.5 游標(biāo)查詢(xún)
/**
* 獲取mongo游標(biāo)(需要手動(dòng)關(guān)閉)
* @param query 查詢(xún)對(duì)象
* @param entityClass 查詢(xún)實(shí)體
* @param batchSize 批次大星妒(默認(rèn)1000饲化,需大于0)
* @param pageNum 當(dāng)前頁(yè)數(shù)
* @param pageSize 每頁(yè)大小
* @return com.mongodb.client.MongoCursor<org.bson.Document>
*/
<T extends MongoBean> MongoCursor<Document> extGetMongoCursor(Query query, Class<T> entityClass, Integer batchSize, Integer pageNum, Integer pageSize){
if(query==null || entityClass==null){
return null;
}
MongoCollection<Document> collection=mongoTemplate.getCollection(mongoTemplate.getCollectionName(entityClass));
FindIterable<Document> findIterable=collection.find(query.getQueryObject());
////----------填充游標(biāo)屬性----------
//(1)游標(biāo)不超時(shí)
findIterable.noCursorTimeout(true);
//(2)批次拉取大小(默認(rèn)1000)
if(batchSize==null || batchSize<=0){
batchSize=DEFAULT_CURSOR_BATCH_SIZE;
}
findIterable.batchSize(batchSize);
//(3)排序
findIterable.sort(query.getSortObject());
//(4)跳過(guò)記錄數(shù)
if(pageNum!=null && pageSize!=null){
findIterable.skip((pageNum - 1) * pageSize);
findIterable.limit(pageSize);
}
return findIterable.cursor();
}
/**
* 執(zhí)行游標(biāo)查詢(xún)
* @param query 查詢(xún)器
* @param entityClass 查詢(xún)實(shí)體
* @param batchSize 批次大小
* @param pageNum 當(dāng)前頁(yè)
* @param pageSize 每次大小
* @param executor 執(zhí)行器
* @return void
*/
public <T extends MongoBean> void extCursorQueryExe(Query query, Class<T> entityClass, Integer batchSize, Integer pageNum, Integer pageSize, Executor<T> executor) throws Exception{
if(executor==null){
return ;
}
try (MongoCursor<Document> cursor = this.extGetMongoCursor(query,entityClass,batchSize,pageNum,pageSize)) {
if(cursor==null){
return ;
}
T model;
while (cursor.hasNext()) {
model = mongoConverter.read(entityClass, cursor.next());
executor.invoke(model);
}
} catch (Exception e) {
throw e;
}
}
----------完整代碼吗伤,可私信聯(lián)系博主----------