1 场景
spring集成mongo后,可以使用mongoTemplate
进行mongo操作。
1.1 当前问题
mongoTemplate写入或者更新数据库时,操作对象
可以是Java bean实体类
也可以是Map对象
。
<T> T insert(T objectToSave);
<T> T insert(T objectToSave, String collectionName);
例子如下:
- 使用map作为存储对象
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","张三");
//年龄为数字:18
map1.put("age",18);
mongoTemplate.insert(map1,"t_user_info");
- 使用java对象作为存储对象
@Data
public class UserInfo{
private String userName;
private Integer age;
}
UserInfo userInfo=new UserInfo();
userInfo.setUserName("张三");
//年龄为数字:18
userInfo.setAge(18);
mongoTemplate.insert(userInfo,"t_user_info");
因为mongo中,同一个表
中,同一个字段
,不同数据
的字段类型
可以不一样。即如上示例,使用map作为存储对象,不同的记录,字段age类型,既可以是字符类型
“18岁”,也可以是数字类型
18,数据库中数据格式如下:
/* 1 */
{
"_id" : ObjectId("5f8107c5f34b265ecada41ff"),
"userName" : "张三",
"age" : "18岁"
}
/* 2 */
{
"_id" : ObjectId("5f8107c5f34b265ecada4200"),
"userName" : "张三",
"age" : 18
}
如只使用java中的bean对象
作为存储对象,则同一个表中所有的数据的数据类型均一致
,如下:
/* 1 */
{
"_id" : ObjectId("5f8107c5f34b265ecada4211"),
"userName" : "张三",
"age" : 18
}
1.2 选型
java中使用map
和自定义bean
都可以作为mongo的存储对象。我们对这两种方式进行对比:
1.2.1 map作为存储对象
- 优点
(1)代码简单,定义map即可存储对象
(2)不用为每个专门的表定义java对象
- 缺点
(1)每次操作数据时,手动定义map的键值。手写代码,容易写错
。字段名容易出错,导致名称相似
的字段出现;字段值的类型
容易出错,导致一个同一个字段不同数据的字段类型不一致
,此问题是非常致命的。
(2)mongo增加字段,无需更改表结构。需额外维护mongo表结构说明文档
,人工通过文档定义字段的名称、含义和类型
。
(3)mongo中增加字段无需更改表结构,不需要DBA授权,对mongo字段如果无限制,如果管理不善,容易出现字段的数量暴增
。
(4)需要人工定义表名称的常量集合。
1.2.1 自定义bean作为存储对象
- 优点
(1)通过mongo表的映射java对象,可以清晰知道mongo表的表结构
(字段名称、字段类型、表名称)
(2)不需要人工定义表名称的常量集合。映射对象上通过注解
或者默认名称
,可以自动获取mongo表的名称。
- 缺点
(1)需要手动为每个表建立专门的java对象
(2)原始的mongoTemplate中api接口无法限制
所有的操作必须使用java对象进行操作。需要人工进行接口的二次封装
(且只能使用封装的接口)。
经过对比,我们选择使用自定义bean
作为存储对象。
2 版本
springBoot:2.2.9.RELEASE
mongodb:4.0
3 步骤
3.1 基础代码
(1)定义java bean的父类
import lombok.Data;
import java.io.Serializable;
/**
* mongo的bean定义
* <br>实现此接口的类,可以进行mongo数据库操作
**/
@Data
public class MongoBean implements Serializable {
/**
* mongo主键(对应数据库中自动生成的字段:_id)
* 此字段不可设置(mongo自己生成)
*/
private String id;
/**
* 删除标志(false:正常;true:删除)
*/
private Boolean delFlag;
/**
* 创建人ID
*/
private String createUserId;
/**
* 创建人姓名
*/
private String createUserName;
/**
* 创建时间
*/
private Integer createDate;
/**
* 更新人ID
*/
private String updateUserId;
/**
* 更新人姓名
*/
private String updateUserName;
/**
* 更新时间
*/
private Integer updateDate;
}
所有的mongo表映射的java对象,均需继承此父类。
如下:
import org.springframework.data.mongodb.core.mapping.Document;
/**
* 用户表
*/
@Document("t_user_info")
public class TUserInfo extends MongoBean {
/**
* 用户名
*/
private String userName;
/**
* 年龄
*/
private Integer age;
}
(2)定义mongo游标执行器
/**
* mongo游标执行器
**/
public interface Executor<T> {
/**
* 执行
* @param cModel 执行实体类
* @return void
*/
void invoke(T cModel) throws Exception;
}
3.2 部分API封装
3.2.1 插入数据
/**
* 插入数据
* @param objectToSave
* @return T
*/
public <T extends MongoBean> T insert(T objectToSave){
return mongoTemplate.insert(objectToSave);
}
/**
* 批量插入数据
* @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 查询数据
/**
* 查询满足条件记录
* @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);
}
/**
* 查询第一条
* @param query
* @param entityClass
* @return T
*/
public <T extends MongoBean> T findOne(Query query, Class<T> entityClass){
return mongoTemplate.findOne(query,entityClass);
}
/**
* 根据主键查询
* @param id
* @param entityClass
* @return T
*/
public <T extends MongoBean> T findById(Object id, Class<T> entityClass){
return mongoTemplate.findById(id,entityClass);
}
/**
* 查询总数
* @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 更新数据
/**
* 更新第一条
* @param query 查询条件
* @param mongoBean 要更新的实体
* @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 查询条件
* @param mongoBean 要更新的实体
* @param updateFields 要更新的字段(有参数时,更新指定的字段;无此参数时,更新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 游标查询
/**
* 获取mongo游标(需要手动关闭)
* @param query 查询对象
* @param entityClass 查询实体
* @param batchSize 批次大小(默认1000,需大于0)
* @param pageNum 当前页数
* @param pageSize 每页大小
* @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());
////----------填充游标属性----------
//(1)游标不超时
findIterable.noCursorTimeout(true);
//(2)批次拉取大小(默认1000)
if(batchSize==null || batchSize<=0){
batchSize=DEFAULT_CURSOR_BATCH_SIZE;
}
findIterable.batchSize(batchSize);
//(3)排序
findIterable.sort(query.getSortObject());
//(4)跳过记录数
if(pageNum!=null && pageSize!=null){
findIterable.skip((pageNum - 1) * pageSize);
findIterable.limit(pageSize);
}
return findIterable.cursor();
}
/**
* 执行游标查询
* @param query 查询器
* @param entityClass 查询实体
* @param batchSize 批次大小
* @param pageNum 当前页
* @param pageSize 每次大小
* @param executor 执行器
* @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;
}
}
----------完整代码,可私信联系博主----------
网友评论