Spring整合MongoDB增删改查及批量新增修改

Posted Lossdate

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring整合MongoDB增删改查及批量新增修改相关的知识,希望对你有一定的参考价值。

简单封装了下基础的增删改查以及批量操作,方便后续的拓展

一、配置

  1. applicationContext.xml

    #beans添加
     xmlns:mongo="http://www.springframework.org/schema/data/mongo"
     http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.5.xsd
    
    #配置
    <mongo:mongo id="mongo" replica-set="${mongo.hostPort}">
    		<!-- 一些连接属性的设置 -->
    		<mongo:options
    				connections-per-host="${mongo.connectionsPerHost}"
    				threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
    				connect-timeout="${mongo.connectTimeout}"
    				max-wait-time="${mongo.maxWaitTime}"
    				auto-connect-retry="${mongo.autoConnectRetry}"
    				socket-keep-alive="${mongo.socketKeepAlive}"
    				socket-timeout="${mongo.socketTimeout}"
    				slave-ok="${mongo.slaveOk}"
    				write-number="1"
    				write-timeout="0"
    				write-fsync="true" />
    	</mongo:mongo>
    
    	<mongo:db-factory dbname="database" mongo-ref="mongo" />
    
    	<bean id="mongoTemplate"
    		  class="org.springframework.data.mongodb.core.MongoTemplate">
    		<constructor-arg name="mongo" ref="mongo" />
    		<constructor-arg name="databaseName" value="test" />
    	</bean>
    
    mongo.hostPort=127.0.0.1:27017
    mongo.connectionsPerHost=8
    mongo.threadsAllowedToBlockForConnectionMultiplier=4
    #连接超时时间
    mongo.connectTimeout=1000
    #等待时间
    mongo.maxWaitTime=1500
    mongo.autoConnectRetry=true
    mongo.socketKeepAlive=true
    #Socket超时时间
    mongo.socketTimeout=1500
    mongo.slaveOk=true
    

二、代码整合

  1. 接口

    /*
     * BaseEntity 为基础实体类,参数随意
     */
    public interface BaseMongoInterface<T extends BaseEntity> {
    
        /**
         * 按 id 查询
         * @param clazz Class
         * @param id 查询的id
         * @param collectionName collectionName
         * @return Entity
         */
        T get(final Class<T> clazz, final String id, final String collectionName);
    
        /**
         * insert
         * @param entity new Entity
         * @param collectionName collectionName
         * @return 1
         */
        int insert(final T entity, final String collectionName);
    
        /**
         * update
         * @param clazz Class
         * @param id update 的 id
         * @param needUpdateParams 需要更新的字段和值
         * @param collectionName collectionName
         * @return count
         */
        int update(final Class<T> clazz, String id, Map<String, Object> needUpdateParams, final String collectionName);
    
        /**
         * find
         * @param clazz Class
         * @param whereParams 查询条件
         * @param sortParam 排序字段
         * @param sortWay 排序方式("ASC", "DESC")
         * @param collectionName collectionName
         * @return List<Entity>
         */
        List<T> find(final Class<T> clazz, Map<String, Object> whereParams, String sortParam, String sortWay, final String collectionName);
    
        /**
         * find one
         * @param clazz Class
         * @param whereParams 查询条件
         * @param sortParam 排序字段
         * @param sortWay 排序方式("ASC", "DESC")
         * @param collectionName collectionName
         * @return Entity
         */
        T findOne(final Class<T> clazz, Map<String, Object> whereParams, String sortParam, String sortWay, final String collectionName);
    
        /**
         * 根据实体 批量 insert
         * @param list 批量插入的实体 list
         * @param collectionName collectionName
         * @return count
         */
        int insertBatch(final List<T> list, final String collectionName);
    
        /**
         * 根据查询条件 批量 update
         * @param clazz Class
         * @param whereParams 查询条件
         * @param needUpdateParams 需要更新的字段
         * @param collectionName collectionName
         * @return count
         */
        int updateBatch(final Class<T> clazz, Map<String, Object> whereParams, Map<String, Object> needUpdateParams, final String collectionName);
    
        /**
         * 根据实体 批量 update
         * @param list 需要 update 的实体 list
         * @param collectionName collectionName
         * @param upsert 实体 id 不存在的情况是否需要插入
         * @param needNullParam 是否更新实体内为null的字段
         * @return count
         */
        int updateBatch(final List<T> list, final String collectionName, boolean upsert, boolean needNullParam);
    
        /**
         * 分页查询
         * @param clazz Class
         * @param whereParams 查询条件
         * @param sortParam 排序字段
         * @param sortWay 排序方式("ASC", "DESC")
         * @param collectionName collectionName
         * @param limitStart 起始
         * @param pageSize 查询多少条
         * @return List<Entity>
         */
        List<T> page(final Class<T> clazz, Map<String, Object> whereParams, String sortParam, String sortWay, final String collectionName, int limitStart, int pageSize);
    
        /**
         * 查询数量
         * @param clazz Class
         * @param whereParams 查询条件
         * @param collectionName collectionName
         * @return count
         */
        long count(final Class<T> clazz, Map<String, Object> whereParams, final String collectionName);
    
        /**
         * 删除
         * @param clazz Class
         * @param whereParams 查询条件
         * @param collectionName collectionName
         * @return count
         */
        int remove(final Class<T> clazz, Map<String, Object> whereParams, final String collectionName);
    }
    
  2. 批量更新工具类

    public class BathUpdateOptions {
        private Query query;
        private Update update;
        private boolean upsert = false;
        private boolean multi = false;
    
        public BathUpdateOptions() {
        }
    
        public BathUpdateOptions(Query query, Update update, boolean upsert, boolean multi) {
            this.query = query;
            this.update = update;
            this.upsert = upsert;
            this.multi = multi;
        }
    	
    	//getter and setter ...
    }
    
    public class BatchUpdateHelper {
    
        public static <T> Map<String, Object> beanToMap(T bean, boolean needNullParam) {
            Map<String, Object> map = Maps.newHashMap();
            if (bean != null) {
                BeanMap beanMap = BeanMap.create(bean);
                for (Object key : beanMap.keySet()) {
                    if(!needNullParam && beanMap.get(key) == null) { continue; }
                    map.put(key + "", beanMap.get(key));
                }
            }
            return map;
        }
    
        public static int bathUpdate(MongoTemplate mongoTemplate,
                                     List<BathUpdateOptions> options,
                                     String collectionName) {
            return doBathUpdate(mongoTemplate.getCollection(collectionName), collectionName, options, true);
        }
    
        private static int doBathUpdate(DBCollection dbCollection, String collName, List<BathUpdateOptions> options, boolean ordered) {
            DBObject command = new BasicDBObject();
            command.put("update", collName);
            List<BasicDBObject> updateList = new ArrayList<>();
            for (BathUpdateOptions option : options) {
                BasicDBObject update = new BasicDBObject();
                update.put("q", option.getQuery().getQueryObject());
                update.put("u", option.getUpdate().getUpdateObject());
                update.put("upsert", option.isUpsert());
                update.put("multi", option.isMulti());
                updateList.add(update);
            }
            command.put("updates", updateList);
            command.put("ordered", ordered);
            CommandResult commandResult = dbCollection.getDB().command(command);
            return Integer.parseInt(commandResult.get("n").toString());
        }
    }
    
  3. 功能实现

    @Component
    public abstract class BaseMongoInterfaceImpl<T extends BaseEntity> implements BaseMongoInterface<T> {
    
        @Autowired
        private MongoTemplate mongoTemplate;
    
        @Override
        public T get(@NotNull Class<T> clazz,
                     @NotNull String id,
                     @NotNull String collectionName) {
            return mongoTemplate.findById(id, clazz, collectionName);
        }
    
        @Override
        public int insert(@NotNull T entity,
                          @NotNull String collectionName) {
            mongoTemplate.insert(entity, collectionName);
            return 1;
        }
    
        @Override
        public int update(@NotNull Class<T> clazz,
                          @NotNull String id,
                          @NotNull Map<String, Object> needUpdateParams,
                          @NotNull String collectionName) {
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(id));
            Update update = new Update();
            needUpdateParams.forEach(update::set);
            WriteResult writeResult = mongoTemplate.updateFirst(query, update, clazz, collectionName);
            return writeResult.getN();
        }
    
        @Override
        public List<T> find(@NotNull Class<T> clazz,
                            Map<String, Object> whereParams,
                            String sortParam,
                            String sortWay,
                            @NotNull String collectionName) {
            Query query = getFindQuery(whereParams, sortParam, sortWay);
    
            return mongoTemplate.find(query, clazz, collectionName);
        }
    
        private Query getFindQuery(Map<String, Object> whereParams, String sortParam, String sortWay) {
            Query query = new Query();
            if (whereParams != null && whereParams.size() > 0) {
                AtomicReference<Criteria> criteria = new AtomicReference<>();
                AtomicInteger index = new AtomicInteger();
                whereParams.forEach((k,v) -> {
                    if(k.equals("id")) { k = "_id"; }
                    if(index.get() == 0) {
                        criteria.set(Criteria.where(k).is(v));
                    } else {
                        criteria.get().and(k).is(v);
                    }
                    index.getAndIncrement();
                });
                query.addCriteria(criteria.get());
            }
    
            if(StringUtils.isNotBlank(sortParam)) {
                if(sortWay == null) {sortWay = "ASC";}
                if("ASC".equals(sortWay)) {
                    query.with(new Sort(new Sort.Order(Sort.Direction.ASC, sortParam)));
                } else {
                    query.with(new Sort(new Sort.Order(Sort.Direction.DESC, sortParam)));
                }
            }
    
            return query;
        }
    
        @Override
        public T findOne(@NotNull Class<T> clazz,
                         @NotNull Map<String, Object> whereParams,
                         String sortParam,
                         String sortWay,
                         @NotNull String collectionName) {
            Query query = getFindQuery(whereParams, sortParam, sortWay);
            query.skip(0);
            query.limit(1);
            List<T> dataList = mongoTemplate.find(query, clazz, collectionName);
            return dataList.isEmpty() ? null : dataList.get(0);
        }
    
    	/**
    	 * 批量操作批次最大数
    	 */
    	public static final Integer BATCH_CEILING = 300;
    	
        @Override
        public int insertBatch(@NotNull List<T> list,
                               @NotNull String collectionName) {
            List<List<T>> batchList = new ArrayList<>();
            int len = BATCH_CEILING;
            if(!list.isEmpty()) {
                if(list.size() > len) {
                    //优化insertBatch,切割处理
                    int size = list.size();
                    int count = (size + len - 1) / len;
                    for (int i = 0; i < count; i++) {
                        List<T> subList = list.subList(i * len, (Math.min((i + 1) * len, size)));
                        batchList.add(subList);
                    }
                    if(batchList.size() > 0) {
                        for (List<T> subList : batchList) {
                            mongoTemplate.insert(subList, collectionName);
                        }
                    }
                } else {
                    mongoTemplate.insert(list, collectionName);
                }
            }
    
            return list.size();
        }
    
        @Override
        public int updateBatch(@NotNull Class<T> clazz,
                               @NotNull Map<String, Object> whereParams,
                               @NotNull Map<String, Object> needUpdateParams,
                               @NotNull String collectionName) {
            Query query = new Query();
            AtomicReference<Criteria> criteria = new AtomicReference<>();
            AtomicInteger index = new AtomicInteger();
            whereParams.forEach((k,v) -> {
                if(index.get() == 0) {
                    criteria.set(Criteria.where(k).is(v));
                } else {
                    criteria.get().and(k).is(v);
                }
                index.getAndIncrement();
            });
            query.addCriteria(criteria.get());
    
            Update update = new Update();
            needUpdateParams.forEach(update::set);
    
            WriteResult writeResult = mongoTemplate.updateMulti(query, update, clazz, collectionName);
    
            return writeResult.getN();
        }
    
        @Override
        public int updateBatch(@NotNull List<T> list,
                               @NotNull String collectionName,
                               @NotNull boolean upsert,
                               @NotNull boolean needNullParam) {
            int result = 0;
            List<BathUpdateOptions> optionsList = new ArrayList<>();
            Map<String, Object> needUpdateParams;
            for (T entity : list) {
                if(StringUtils.isBlank(entity.getId())) { continue; }
                Query query = new Query();
                query.addCriteria(Criteria.where("_id").is(entity.getId()));
                entity.setId(null);
                needUpdateParams = BatchUpdateHelper.beanToMap(entity, needNullParam);
                Update update = new Update();
                needUpdateParams.forEach(update::set);
    
                optionsList.add(new BathUpdateOptions(query, update, upsert, true));
            }
    
            List<List<BathUpdateOptions>> batchList = new ArrayList<>();
            int len = BATCH_CEILING;
            if(!optionsList.isEmpty()) {
                if(optionsList.size() > len) {
                    //优化insertBatch,切割处理
                    int size = optionsList.size();
                    int count = (size + len - 1) / len;
                    for (int i = 0; i < count; i++) {
                        List<BathUpdateOptions> subList = optionsList.subList(i * len, (Math.min((i + 1) * len, size)));
                        batchList.add(subList);
                    }
                    if(batchList.size() > 0) {
                        for (List<BathUpdateOptions> subList : batchList) {
                            result += BatchUpdateHelper.bathUpdate(mongoTemplate, subList, collectionName);
                        }
                    }
                } else {
                    result = BatchUpdateHelper.bathUpdate(mongoTemplate, optionsList, collectionName);
                }
            }
    
            return result;
        }
    
        @Override
        public List<T> page(@NotNull Class<T> clazz,
                            Map<String, Object> whereParams,
                            String sortParam,
                            String sortWay,
                            @NotNull final String collectionName,
                            @NotNull int limitStart,
                            @NotNull int pageSize) {
            Query query = getFindQuery(whereParams, sortParam, sortWay);
            query.skip(limitStart);
            query.limit(pageSize);
            return mongoTemplate.find(query, clazz, collectionName);
        }
    
        @Override
        public long count(@NotNull Class<T> clazz,
                          @NotNull Map<String, Object> whereParams,
                          @NotNull final String collectionName) {
            Query query = getFindQuery(whereParams, null, null);
            return mongoTemplate.count(query, clazz, collectionName);
        }
    
        @Override
        public int remove(@NotNull Class<T> clazz,
                          @NotNull Map<String, Object> whereParams,
                          @NotNull final String collectionName) {
            Query query = getFindQuery(whereParams, null, null);
            WriteResult remove = mongoTemplate.remove(query, clazz, collectionName);
            return remove.getN();
        }
    }
    

以上是关于Spring整合MongoDB增删改查及批量新增修改的主要内容,如果未能解决你的问题,请参考以下文章

Spring整合MongoDB增删改查及批量新增修改

04-springboot整合elasticsearch初识-简单增删改查及复杂排序,分页,聚合操作

python课堂整理34----类的增删改查及实例属性增删改查

简单的增删改查及数据分页

Python字典的初识增删改查及嵌套

yii2增删改查及AR的理解