mongodb 3.2 实战(三)整合Spring Data MongoDB
2017-01-04 14:58
609 查看
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.mongodb.com/manual/tutorial/perform-two-phase-commits/
对于这个MongoDB事务,个人的观点是不建议使用事务,因为在数据库选型的时候,如果希望事务比较强,那么建议选用关系型数据库来存储数据。对于MongoDB的应用,一般是用来查询,或者是存储日志等对事务要求比较弱的应用场景。
2.spring data MongoDB 整合
环境:
spring.data.mongodb.1.7.2.RELEASE.jarmongo-java-driver-2.13.3.jar
配置连接池:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/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。
相关文章推荐
- MongoDB简介
- mongodb备份和恢复
- Python MongoDB 安装以及使用
- 高并发读与高并发写的项目总结和mongodb使用中遇到的坑
- Windows下MongoDB安装与配置
- Spring 整合 MongoDB
- 从mongoDB导出数据
- Nodejs + mongoDB 使用初体验
- Python MongoDB使用介绍
- 获取Unix时间戳(Unix timestamp):
- CentOS安装MongoDB
- monggodb学习系列:1,mongodb入门
- Spring Data 与MongoDB 集成一:入门篇(开发环境搭建和简单CRUD)
- MongoDb导出数据.CSV格式到EXCEL
- MONGODB简单操作命令
- Spring Boot中使用MongoDB数据库
- 初学mongodb笔记
- ubuntu16.04文件形式安装mongodb
- MongoDB数字类型保留2位小数
- 13 MongoDB