车险小周 發表於 2020-10-16 11:29:00

MongoDB SpringBoot 批量更新

<ul>
<li>最近考虑对原有得Mongo库操作进行优化,老的逻辑会频繁得操纵库,而且还是单条得,性能担忧啊,所以考虑将单条更新转换成批量更新,话不多说,直接上代码.</li>
</ul>
<ol>
<li>添加一个供批量操作得对象</li>
</ol>
<pre><code>@Data
@NoArgsConstructor
@AllArgsConstructor
public class BatchUpdateOptions {
    private Query query;
    private Update update;
    private boolean upsert = true;
    private boolean multi = false;
}
</code></pre>
<ol start="2">
<li>创建批量操作的Dao</li>
</ol>
<pre><code>public class MongoBaseDao {
    /**
   * 批量更新
   * @param ordered 如果为true,一条语句更新失败,剩下的语句将不再执。如果为false,一条语句更新失败,剩下的将继续执行。默认为true。
   * @return
   */
    public static int batchUpdate(MongoTemplate mongoTemplate, String collectionName, List&lt;BatchUpdateOptions&gt; options, boolean ordered) {
      return doBatchUpdate(mongoTemplate, collectionName, options, ordered);
    }
    private static int doBatchUpdate(MongoTemplate mongoTemplate, String collName, List&lt;BatchUpdateOptions&gt; options, boolean ordered) {
      try{
            //      BasicDBObject command = new BasicDBObject();
            Document command = new Document();
            command.put("update", collName);
            List&lt;Document&gt; updateList = options.stream().map(option -&gt; {
                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;
    }
</code></pre>
<ol start="3">
<li>Test</li>
</ol>
<pre><code>List&lt;User&gt; userList = new ArrayList();
User us = new User();
us.setId(1);
us.setName("张三");
userList.add(us);

List&lt;BatchUpdateOptions&gt; collect = userList.stream().map(user -&gt; {
        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);
</code></pre>
<ol start="4">
<li>添加一个工具类</li>
</ol>
<pre><code>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 &amp; 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;
    }
}
</code></pre>
<ol start="5">
<li>注意事项</li>
</ol>
<pre><code>update.set(key, mongoConverter.convertToMongoType(value));
</code></pre>
<p>这句代码,如果不使用mongoConverter.convertToMongoType 进行转换,部分类型MongoDB 无法直接转换,在执行</p>
<pre><code>Document document = mongoTemplate.getDb().runCommand(command);
</code></pre>
<p>就会报错,报错内容大致是:</p>
<pre><code>org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class com.cn.local.list……
</code></pre>
<p><strong>6. 所以一定要使用 mongoConverter.convertToMongoType(obj) 来设置 update的的value值.</strong></p><br><br>
来源:https://www.cnblogs.com/joinlemon/p/13825540.html
頁: [1]
查看完整版本: MongoDB SpringBoot 批量更新