分享

mongodb 3.2 实战(三)整合Spring Data MongoDB

 Bladexu的文库 2019-04-10

1.简介

Spring Data for MongoDB 作为 Spring 大家族中的一员,为MongoDB定制了类似于关系型数据库的ORM框架。

  • 与hibernate mybatis 等ORM框架类似,都需要一个pojo的bean。所不同的是,关系型数据库对应的是table,而此处对应到MongoDB中的collection。

  • 由于 MongoDB 本身并没有事务支持,所以spring 也无法维护事务。但是在mongoDB的操作手册提供了这样一个方式来维护多文档操作的事务。

原文是这样说的:


Because only single-document operations are atomic with MongoDB, two-phase commits can
only offer transaction-like semantics. It is possible for applications to return intermediate data at
intermediate points during the two-phase commit or rollback.


只有单文档操作是原子性的,两阶段提交可以提供这样一个类似事务的模式。这样来为应用程序可以返回一个再两阶段提交或者回滚的中间点。直接略去我的翻译,大致的意思,就是MongoDB仅仅支持单文档的原子性操作,但是提供了一个两阶段方式来维护事务。也就是说在多个文档操作时,MongoDB提供了一个两阶段提交模式来维护事务。

具体的操作方式,具体参考一下
https://docs./manual/tutorial/perform-two-phase-commits/
对于这个MongoDB事务,个人的观点是不建议使用事务,因为在数据库选型的时候,如果希望事务比较强,那么建议选用关系型数据库来存储数据。对于MongoDB的应用,一般是用来查询,或者是存储日志等对事务要求比较弱的应用场景。

2.spring data MongoDB 整合

环境:

spring.data.mongodb.1.7.2.RELEASE.jar
mongo-java-driver-2.13.3.jar

配置连接池:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www./schema/beans"
    xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:context="http://www./schema/context"
    xmlns:mongo="http://www./schema/data/mongo"
    xsi:schemaLocation="http://www./schema/beans
            http://www./schema/beans/spring-beans-4.1.xsd
            http://www./schema/context
            http://www./schema/context/spring-context-4.1.xsd
            http://www./schema/data/mongo
           http://www./schema/data/mongo/spring-mongo-1.0.xsd">

    <!-- 配置mongoTemplate -->
    <mongo:mongo host="${mongo.host}" port="${mongo.port}"></mongo:mongo>


    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg ref="mongo" />
        <constructor-arg name="databaseName" value="${mongo.dbname}" />
    </bean>

</beans>

MongoTemplate 是spring data MongoDB 中的的操作类,继承了MongoOperations 与ApplicationContextAware ,这个MongoOperations里面封装了基础CRUD操作,有兴趣直接阅读以下源码很快能看懂。

基础的操作接口

package edu.yingding.core.mongo;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import edu.yingding.core.entity.PagerDTO;

//mongo操作接口
public interface IBaseMongo {

    public List selectPage(Map<String, Object> param, Class entityClass,  PagerDTO pagerDto) throws Exception;

    public List selectPage(String queryStr, Class entityClass,  PagerDTO pagerDto) throws Exception;

    List find( Query query,Class entityClass);

    public List selectPage(Query query,Class entityClass,PagerDTO pagerDto)throws Exception;

    /**
     * 分组取数据
     * @param collectionName mongo表名
     * @param fieldName
     * @param param
     * @return
     * @throws Exception
     */
    public List distinct(String collectionName, String fieldName, Map<String, Object> param) throws Exception;

    /**
     * 得到一个实体
     * @param param
     * @param entityClass
     * @return
     * @throws Exception
     */
    public Object findOne(Map<String, Object> param, Class entityClass) throws Exception;

    /**
     * 保存结果集
     * @param entity
     * @return
     * @throws Exception
     */
    public boolean insert(Object entity) throws Exception;

    /**
     * 按id更新数据
     * @param id
     * @param param
     * @return
     * @throws Exception
     */
    public boolean updateById(String id, Map<String, Object> param, Class entityClass) throws Exception;


    List selectPage(String queryStr, Criteria criteria, Class entityClass, PagerDTO pagerDto) throws Exception;
}
package edu.yingding.core.mongo;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import com.mongodb.WriteResult;
import edu.yingding.core.entity.PagerDTO;
import net.sf.json.JSONObject;

/**
 * @Author:chenfanglin 【chenfanglincfl@163.com】
 * @Description:
 * @Date: 15:53 2017/1/4
 * @Version 1.0.0
 */
@Service
public class BaseMongoImpl implements IBaseMongo {

    @Autowired
    protected MongoTemplate mongoTemplate;

    /**
     * @param param       查询参数【map类型】
     * @param entityClass 反射类
     * @param pagerDto    分页实体
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 分页方法【支持map类型参数】
     * @Date: 15:52 2017/1/4
     * @Version 1.0.0
     */
    @Override
    public List selectPage(Map<String, Object> param, Class entityClass, PagerDTO pagerDto) throws Exception {
        Query query = parseParams(param);

        long total = mongoTemplate.count(query, entityClass);
        List results = null;
        if (total > 0) {
            pagerDto.init(total);
            query.skip((pagerDto.getPageNum() - 1) * pagerDto.getPageSize());
            query.limit(pagerDto.getPageSize());

            if (StringUtils.isNotEmpty(pagerDto.getOrderBy())) {
                JSONObject orderObj = JSONObject.fromObject(pagerDto.getOrderBy());
                if (orderObj != null) {
                    Iterator it = orderObj.keys();
                    while (it.hasNext()) {
                        String key = (String) it.next();
                        int value = orderObj.getInt(key);
                        if (value == 1) {
                            query.with(new Sort(Direction.ASC, key));
                        } else {
                            query.with(new Sort(Direction.DESC, key));
                        }
                    }
                }
            }

            System.out.println(query.toString());
            results = mongoTemplate.find(query, entityClass);
            pagerDto.setResult(results);
        } else {
            pagerDto.setResult(Collections.emptyList());
        }
        return results;
    }

    /**
     * @param queryStr    查询字符串
     * @param entityClass 反射类
     * @param pagerDto    分页实体
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 分页方法 【支持查询字符串】
     * @Date: 15:54 2017/1/4
     * @Version 1.0.0
     */
    @Override
    public List selectPage(String queryStr, Class entityClass, PagerDTO pagerDto) throws Exception {
        if (queryStr == null) {
            queryStr = "";
        }
        BasicQuery query = new BasicQuery(queryStr);
        long total = mongoTemplate.count(query, entityClass);
        List results = null;
        if (total > 0) {
            pagerDto.init(total);
            query.skip((pagerDto.getPageNum() - 1) * pagerDto.getPageSize());
            query.limit(pagerDto.getPageSize());

            if (StringUtils.isNotEmpty(pagerDto.getOrderBy())) {
                JSONObject orderObj = JSONObject.fromObject(pagerDto.getOrderBy());
                if (orderObj != null) {
                    Iterator it = orderObj.keys();
                    while (it.hasNext()) {
                        String key = (String) it.next();
                        int value = orderObj.getInt(key);
                        if (value == 1) {
                            query.with(new Sort(Direction.ASC, key));
                        } else {
                            query.with(new Sort(Direction.DESC, key));
                        }
                    }
                }
            }
            results = mongoTemplate.find(query, entityClass);
            pagerDto.setResult(results);
        } else {
            pagerDto.setResult(Collections.emptyList());
        }
        return results;
    }

    /**
     * @param queryStr
     * @param criteria
     * @param entityClass
     * @param pagerDto
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 分页方法 【支持查询字符串与Criteria对象】
     * @Param:
     * @Date: 15:55 2017/1/4
     * @Version 1.0.0
     */
    @Override
    public List selectPage(String queryStr, Criteria criteria, Class entityClass, PagerDTO pagerDto) throws Exception {
        if (queryStr == null) {
            queryStr = "";
        }
        BasicQuery query = new BasicQuery(queryStr);
        query.addCriteria(criteria);
        long total = mongoTemplate.count(query, entityClass);
        List results = null;
        if (total > 0) {
            pagerDto.init(total);
            query.skip((pagerDto.getPageNum() - 1) * pagerDto.getPageSize());
            query.limit(pagerDto.getPageSize());

            if (StringUtils.isNotEmpty(pagerDto.getOrderBy())) {
                JSONObject orderObj = JSONObject.fromObject(pagerDto.getOrderBy());
                if (orderObj != null) {
                    Iterator it = orderObj.keys();
                    while (it.hasNext()) {
                        String key = (String) it.next();
                        int value = orderObj.getInt(key);
                        if (value == 1) {
                            query.with(new Sort(Direction.ASC, key));
                        } else {
                            query.with(new Sort(Direction.DESC, key));
                        }
                    }
                }
            }
            results = mongoTemplate.find(query, entityClass);
            pagerDto.setResult(results);
        } else {
            pagerDto.setResult(Collections.emptyList());
        }
        return results;
    }

    /**
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 查询实体list
     * @Param: query 查询对象
     * @Param: entityClass 反射类
     * @Date: 15:57 2017/1/4
     * @Version 1.0.0
     */
    @Override
    public List find(Query query, Class entityClass) {
        return mongoTemplate.find(query, entityClass);
    }

    /**
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 查询分页 【支持query对象】
     * @Param: * @param query 查询对象
     * @Param: * @param entityClass 反射类
     * @Param: * @param pagerDto 分页实体
     * @Date: 15:58 2017/1/4
     * @Version 1.0.0
     */
    @Override
    public List selectPage(Query query, Class entityClass, PagerDTO pagerDto) throws Exception {
        List results = null;
        if (query != null) {
            long count = mongoTemplate.count(query, entityClass);
            if (count > 0) {
                pagerDto.init(count);
                query.skip((pagerDto.getPageNum() - 1) * pagerDto.getPageSize());
                query.limit(pagerDto.getPageSize());
                if (StringUtils.isNotEmpty(pagerDto.getOrderBy())) {
                    JSONObject orderObj = JSONObject.fromObject(pagerDto.getOrderBy());
                    if (orderObj != null) {
                        Iterator it = orderObj.keys();
                        while (it.hasNext()) {
                            String key = (String) it.next();
                            int value = orderObj.getInt(key);
                            if (value == 1) {
                                query.with(new Sort(Direction.ASC, key));
                            } else {
                                query.with(new Sort(Direction.DESC, key));
                            }
                        }
                    }
                }

                System.out.println(query.toString());
                results = mongoTemplate.find(query, entityClass);
                pagerDto.setResult(results);
            } else {
                pagerDto.setResult(Collections.emptyList());
            }
        } else {
            pagerDto.setResult(Collections.EMPTY_LIST);
        }
        return results;
    }

    /**
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 查询去重实体集合
     * @Param: * @param collectionName 集合名称
     * @Param: * @param fieldName 去重字段名
     * @Param: * @param param 查询条件
     * @Date: 15:59 2017/1/4
     * @Version 1.0.0
     */
    @Override
    public List distinct(String collectionName, String fieldName, Map<String, Object> param) throws Exception {
        if (StringUtils.isEmpty(collectionName) || StringUtils.isEmpty(fieldName)) {
            return Collections.emptyList();
        }
        Query query = parseParams(param);
        return mongoTemplate.getCollection(collectionName).distinct(fieldName, query.getQueryObject());
    }

    /**
     * @Author:chenfanglin 【chenfanglincfl@163.com】
     * @Description: 格式化查询条件
     * @Param: * @param param 查询条件
     * @Date: 16:00 2017/1/4
     * @Version 1.0.0
     */
    private Query parseParams(Map<String, Object> param) {
        Query query = new Query();
        if (param != null && !param.isEmpty()) {
            Iterator<Map.Entry<String, Object>> it = param.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                if (StringUtils.isEmpty(key)) {
                    continue;
                }
                if (key.endsWith("Ignore")) {
                    continue;
                }
                if (key.startsWith("$")) {
                } else if (key.endsWith("Contains")) {
                    query.addCriteria(Criteria.where(key.replaceFirst("Contains", "")).regex((String) entry.getValue()));
                } else {
                    query.addCriteria(Criteria.where(key).is(entry.getValue()));
                }
            }
        }
        return query;
    }

    @Override
    public Object findOne(Map<String, Object> param, Class entityClass) throws Exception {
        Query query = parseParams(param);
        return mongoTemplate.findOne(query, entityClass);
    }

    @Override
    public boolean insert(Object entity) throws Exception {
        try {
            mongoTemplate.insert(entity);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean updateById(String id, Map<String, Object> param, Class entityClass) throws Exception {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        Update update = parseUpdate(param);
        WriteResult result = mongoTemplate.updateFirst(query, update, entityClass);
        return result.getN() > 0 ? true : false;
    }

    private Update parseUpdate(Map<String, Object> param) {
        Update update = new Update();
        if (param != null && !param.isEmpty()) {
            Iterator<Map.Entry<String, Object>> it = param.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                if (StringUtils.isEmpty(key)) {
                    continue;
                }
                if (key.endsWith("Ignore")) {
                    continue;
                }
                if (key.startsWith("$")) {
                } else {
                    update.set(key, entry.getValue());
                }
            }
        }
        return update;
    }
}

分页实体

    package edu.yingding.core.entity;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

/**
* @Author:chenfanglin 【chenfanglincfl@163.com】
* @Description:  分页实体
* @Param:  * @param null
* @Date: 16:01 2017/1/4
* @Version 1.0.0
*/
public class PagerDTO {

    //当前第几页
    private int pageNum=1;

    //总共多少页
    private long pageCount;

    //每页显示几条数据
    private int pageSize = 10;

    //总共多少条
    private long total;

    /* 排序方式 */
    private String orderBy;

    /* 查询字符串 */
    private String queryStr;

    /* 表单防止重复提交码 */
    private String formToken;

    /* 必须有参数才能做分页查询 */
    private boolean argsCanSearch;

    /* 如果为真,并且pageCount > 0 ,则在数据库中不进行查询 */
    private boolean userPageCount;

    //分页返回的数据
    private Object result;

    public boolean isUserPageCount() {
        return userPageCount;
    }

    public void setUserPageCount(boolean userPageCount) {
        this.userPageCount = userPageCount;
    }

    public boolean isArgsCanSearch() {
        return argsCanSearch;
    }

    public void setArgsCanSearch(boolean argsCanSearch) {
        this.argsCanSearch = argsCanSearch;
    }

    public String getFormToken() {
        return formToken;
    }

    public void setFormToken(String formToken) {
        this.formToken = formToken;
    }

    public void init(long total) {
        this.setTotal(total);
        boolean flag = (total%this.getPageSize() == 0) ? false : true;
        long iPageSize = flag ? (total/this.getPageSize()+1) : (total/this.getPageSize());
        if(this.getPageNum() > iPageSize) {
            this.setPageNum(1);
        }
        this.setPageCount(iPageSize);
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public long getPageCount() {
        return pageCount;
    }

    public void setPageCount(long pageCount) {
        this.pageCount = pageCount;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPerPage(int pageSize) {
        if(pageSize > 100) {
            this.pageSize = 100;
        } else {
            this.pageSize = pageSize;
        }
    }

    public long getTotal() {
        return total;
    }

    public void setTotal(long total) {
        this.total = total;
    }

    public String getOrderBy() {
        return orderBy;
    }

    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }

    public String getQueryStr() {
        return queryStr;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    public String getEncodeQueryStr() {
        if(queryStr != null && !"".equals(queryStr)) {
            try {
                return URLEncoder.encode(queryStr, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    public String getDecodeQueryStr() {
        if(queryStr != null && !"".equals(queryStr)) {
            try {
                return URLDecoder.decode(queryStr, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    public void setQueryStr(String queryStr) {
        this.queryStr = queryStr;
    }

    public String getCacheString() {
        StringBuffer cacheKey = new StringBuffer();
        cacheKey.append(this.getPageNum()).append("#");
        cacheKey.append(this.getPageSize()).append("#");
        if(StringUtils.isNotEmpty(this.getOrderBy())) {
            cacheKey.append(this.getOrderBy()).append("#");
        }
        List<String> args = new ArrayList<String>();
        setCacheList(args);
        if(args != null && !args.isEmpty()) {
            for(String arg : args) {
                if(StringUtils.isNotEmpty(arg)) {
                    cacheKey.append(arg).append("#");
                }
            }
        }
        return cacheKey.toString();
    }

    /**
     * 设置缓存KEY
     * @param cacheKeys
     */
    public void setCacheList(List<String> args) {

    }

}

总结

总的来说,Spring Data MongoDB 整体架构方式还是类似于hibernate mybatis,只是相应的会有一些概念的变动。就操作性来说,对于开发人员只是熟悉相关API以及相关的概念,触类旁通。使用来说还是很方便的。

扩展:
诸如类似Spring Data MongoDB ORM 框架还有诸如 morphia
https://github.com/mongodb/morphia

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多