您的位置:首页 > 数据库 > Mongodb

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.jar

mongo-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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: