MongoDB SpringBoot 批量更新
- 最近考虑对原有得Mongo库操作进行优化,老的逻辑会频繁得操纵库,而且还是单条得,性能担忧啊,所以考虑将单条更新转换成批量更新,话不多说,直接上代码.
- 添加一个供批量操作得对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BatchUpdateOptions {
private Query query;
private Update update;
private boolean upsert = true;
private boolean multi = false;
}
- 创建批量操作的Dao
public class MongoBaseDao {
/**
* 批量更新
* @param ordered 如果为true,一条语句更新失败,剩下的语句将不再执。如果为false,一条语句更新失败,剩下的将继续执行。默认为true。
* @return
*/
public static int batchUpdate(MongoTemplate mongoTemplate, String collectionName, List<BatchUpdateOptions> options, boolean ordered) {
return doBatchUpdate(mongoTemplate, collectionName, options, ordered);
}
private static int doBatchUpdate(MongoTemplate mongoTemplate, String collName, List<BatchUpdateOptions> options, boolean ordered) {
try{
// BasicDBObject command = new BasicDBObject();
Document command = new Document();
command.put("update", collName);
List<Document> updateList = options.stream().map(option -> {
Document update = new Document();
update.put("q", option.getQuery().getQueryObject());
update.put("u", option.getUpdate().getUpdateObject());
update.put("upsert", option.isUpsert());
update.put("multi", option.isMulti());
return update;
}).collect(Collectors.toList());
command.put("updates", updateList);
command.put("ordered", ordered);
Document document = mongoTemplate.getDb().runCommand(command);
System.out.println("doc:"+document);
System.out.println("doc--n:"+document.get("n"));
System.out.println("doc--nModified:"+document.get("nModified"));
// n为符合Query查询的记录总数 因为是根据id进行的查询, 原则上只要符合查询的记录数等于要更新的数量就代表成功
Object n = document.get("n");
System.out.println("doc--n--class:"+n.getClass());
if(n.getClass()==Integer.class){
return (Integer)n;
}
return Integer.parseInt(String.valueOf(n));
}catch (Exception e){
e.printStackTrace();
}
return 0;
}
- Test
List<User> userList = new ArrayList();
User us = new User();
us.setId(1);
us.setName("张三");
userList.add(us);
List<BatchUpdateOptions> collect = userList.stream().map(user -> {
Update update = BeanConversionValue.setUpdateValue(user,mongoConverter);
Query query = Query.query(Criteria.where("id").is(user.getId()).and("name").is("张三"));
return new BatchUpdateOptions(query, update, true, true);
}).collect(Collectors.toList());
int num = MongoBaseDao.batchUpdate(mongoTemplate, HotelConstant.EBK_INVENTORY_COLLECTION, collect, true);
System.out.println("更新数量是:{}",num);
- 添加一个工具类
public class BeanConversionValue {
public static Update setUpdateValue(Object op,MongoConverter mongoConverter){
Update update = new Update();
Field[] declaredFields = op.getClass().getDeclaredFields();
for(Field field: declaredFields){
String key = field.getName();// 获取属性名
String method = key.substring(0,1).toUpperCase()+key.substring(1);// 将属性首字符大写,方便get & set 方法
try {
Method setmethod = null;
if(StringUtils.equals(field.getType().getName(),"boolean")){
setmethod = op.getClass().getMethod("is"+method);// 获取 get 方法
}else{
setmethod = op.getClass().getMethod("get"+method);// 获取 get 方法
}
Object value = setmethod.invoke(op);// 通过 get 获取值
System.out.println(key + "--" + value);
if(!StringUtils.equalsIgnoreCase("id",key)){
update.set(key, mongoConverter.convertToMongoType(value));
}
} catch (Exception e) {
e.printStackTrace();
Sentry.capture(e);
}
}
return update;
}
}
- 注意事项
update.set(key, mongoConverter.convertToMongoType(value));
这句代码,如果不使用mongoConverter.convertToMongoType 进行转换,部分类型MongoDB 无法直接转换,在执行
Document document = mongoTemplate.getDb().runCommand(command);
就会报错,报错内容大致是:
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class com.cn.local.list……
6. 所以一定要使用 mongoConverter.convertToMongoType(obj) 来设置 update的的value值.