SpringBoot整合mongodb

mongodb作为文档型数据库,是最像关系型数据库的。

1,pom.xml

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
	<!-- 引入mongodb starter -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

2,application.properties


# MongoDB
spring.data.mongodb.uri=mongodb://localhost:27017/test

#logging.level.com.example.demo=debug
logging.level.org.springframework.data.mongodb.core.MongoTemplate=debug

3,实体

import org.springframework.data.annotation.Id;
//指明集合名
@Document(collection="user")
public class User{
	//指定id
	@Id
	private String id;
	private String password;
	private String name;
	private String gender;
	private Date createTime;
//get/set
}

@Document(collection="order")
public class Order {
	
	@Id
	private String id;
	private String shopName;
	//关联user集合
	@DBRef
	private User user;
//get/set
}

public class GroupResult {

	private Integer count;
	private String groupName;
//get/set
}

4,工具类


import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 发射可以说是java提供给程序员的作弊器了,
 * 利用反射可以创建并调用bean的私有方法,
 * 但这样就破坏了java的封装性,而且反射是 比较耗资源的
 * 使用要谨慎
 * @author 25395
 *
 */
public class ReflectUtil {
	
	/**
	 * 将实体中有值的属性放到map中
	 * @param object
	 * @return
	 */
	public static Map<String,Object> entryToMap(Object object){
		Map<String,Object> map=new HashMap<>();
		try {
			Field[] fields = object.getClass().getDeclaredFields();
			Object result=null;
			for(Field field: fields) {
				field.setAccessible(true);
				result = field.get(object);
				if(result!=null) {
					map.put(field.getName(), result);
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}	

}

5,工具方法抽取

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.aggregation.UnwindOperation;
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.util.StringUtils;

import com.example.demo.bean.GroupResult;
import com.example.demo.util.ReflectUtil;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;


public class MongodbServiceImpl {
	
	@Autowired
	private MongoTemplate mongoTemplate;
	/**
	 * 带条件分组
	 * @param criteria
	 * @param filed
	 * @param collectionName
	 * @return
	 */
	protected List<GroupResult> groupBy(Criteria criteria, String filed,String collectionName) {  
		MatchOperation match = Aggregation.match(criteria);
		GroupOperation groupOperation = Aggregation.group(filed).count()  
				.as("count");  
		ProjectionOperation project = Aggregation.project("count").and("_id")  
				.as("groupName");  
		
		Aggregation agg = Aggregation.newAggregation(match,groupOperation,project);  
		
		AggregationResults<GroupResult> results = mongoTemplate  
				.aggregate(agg, collectionName, GroupResult.class);  
		List<GroupResult> mappedResults = results.getMappedResults();  
		return mappedResults;  
	}  
	/**
	 * 根据传入的字段,对集合进行分组
	 * @param filed:待分组的字段
	 * @param collectionName:集合名
	 * @return:[{_id=女, count=2, groupName=女}]
	 */
	protected List<GroupResult> groupBy(String filed,String collectionName) {  
       GroupOperation groupOperation = Aggregation.group(filed).count()  
                .as("count");  
       ProjectionOperation project = Aggregation.project("count").and("_id")  
                .as("groupName");  
  
       Aggregation agg = Aggregation.newAggregation(groupOperation,project);  
  
       AggregationResults<GroupResult> results = mongoTemplate  
                .aggregate(agg, collectionName, GroupResult.class);  
       List<GroupResult> mappedResults = results.getMappedResults();  
       return mappedResults;  
    }  
	/**
	 * 内嵌集合分组查询
	 * @param filed 待分组字段,即要分组的字段 如:products.category
	 * @param collectionName 集合名
	 * @return
	 */
	protected List<GroupResult> innerGroupBy(String filed,String collectionName) { 
		String[] fileds = filed.split("\\.");	   
		UnwindOperation unwind = Aggregation.unwind(fileds[0]);
		GroupOperation groupOperation = Aggregation.group(filed).count()  
				.as("count");  
		ProjectionOperation project = Aggregation.project("count").and("_id")  
				.as("groupName");  
		
		Aggregation agg = Aggregation.newAggregation(unwind,groupOperation,project);  
		
		AggregationResults<GroupResult> results = mongoTemplate  
				.aggregate(agg, collectionName, GroupResult.class);  
		List<GroupResult> mappedResults = results.getMappedResults();  
		return mappedResults;  
	}  
	/**
	 * 根据传入实体,利用反射进行查询
	 * @param object
	 * @param page
	 * @return
	 */
	protected Page<?> findAll(Object object, Pageable page) {
		Criteria criatira=new Criteria();
		try {
			Field[] fields = object.getClass().getDeclaredFields();
			for(Field field : fields) {
				field.setAccessible(true);
				Object val = field.get(object);
				if(val != null) {
					String key = field.getName();
					criatira.and(key).is(val);
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return findAll(criatira, page,object.getClass());
	}
	/**
	 * 根据传入的查询条件,进行查询
	 * @param criatira
	 * @param page
	 * @param entityClass
	 * @return
	 */
	protected <K> Page<K> findAll(Criteria criatira, Pageable page, Class<K> entityClass) {
		 Query query = new Query(criatira);
		 long totalCount = this.mongoTemplate.count(query, entityClass);//查询数量
		 Page<K> pages;
		 List<K> list;
		 if (totalCount > 0) {
			 list = mongoTemplate.find(query.with(page), entityClass);
			 pages = new PageImpl<>(list, page, totalCount);
		 } else {
			 pages = new PageImpl<>(Collections.emptyList());
		 }
		 return pages;
	 }
	/**
	 * 查询所有满足条件的记录,不分页
	 * @param criatira
	 * @param entityClass
	 * @return
	 */
	protected <K> List<K> findAll(Criteria criatira, Class<K> entityClass) {
		Query query = new Query(criatira);
		List<K> list = mongoTemplate.find(query, entityClass);
		return list;
	}
	/**
	 * 根据id进行有选择地更新,如果entry属性值为空,则将该值设置为空(当只有一列时,会删除该列)
	 * @param id
	 * @param map
	 * @param entityClass
	 */
    protected long updateById(Object id, Map<String, Object> map, Class<?> entityClass) {
        Update update = new Update();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null == entry.getValue()) {
                update.unset(entry.getKey());
            } else {
                update.set(entry.getKey(), entry.getValue());
            }
        }

        UpdateResult updateMulti = mongoTemplate.updateMulti(new Query(Criteria.where("_id").is(id)), update, entityClass);
        return updateMulti.getModifiedCount();
    }
    
    /**
     * 指定更新對象的id 的名,根據傳入對象有選擇地更新
     * @param object :更新的對象
     * @param idName : id名
     */
    protected  long updateByEntry(Object object,String idName) {
    	Map<String, Object> map = ReflectUtil.entryToMap(object);
    	if(!StringUtils.hasText(idName)) {
    		idName="id";
    	}
    	Object idVal = map.get(idName);
    	map.remove(idName);
    	return updateById(idVal, map, object.getClass());
    }
    
    /**
     * 根據傳入對象有選擇地更新(主键的key 默认为:id)
     * @param object :更新的對象
     */
    protected  long updateByEntry(Object object) {
    	return updateByEntry(object,null);
    }
    
    /**
     * 根据传入的ids 对指定集合进行删除
     * @param ids
     * @param entityClass
     * @param idName
     * @return 删除的条数
     */
    protected  long remove(List<Object> ids,Class<?> entityClass,String idName) {
    	if(!StringUtils.hasText(idName)) {
    		idName="id";
    	}
    	Criteria criatira=Criteria.where(idName).in(ids);
    	Query query = new Query(criatira);
    	DeleteResult result = mongoTemplate.remove(query, entityClass);
    	return result.getDeletedCount();
    }
    /**
     * 根据传入的ids 对指定集合进行删除,注解默认为:id
     * @param ids
     * @param entityClass
     * @return 删除的条数
     */
    protected  long remove(List<Object> ids,Class<?> entityClass) {
    	return remove(ids, entityClass, null);
    }
    /**
     * 保存单个实体
     * @param objectToSave
     */
    protected  void insert(Object objectToSave) {
    	mongoTemplate.insert(objectToSave);
    }
    /**
     * 保存实体集合
     * @param objectsToSave
     */
    protected void insertAll(Collection<? extends Object> objectsToSave) {
    	mongoTemplate.insertAll(objectsToSave);
	}
}

6,测试类

import java.util.List;
import java.util.Map;

import org.springframework.data.domain.Page;

import com.example.demo.bean.User;

public interface UserService {

	void update(User user);

	Page<User> query(User user,Page<User> page) ;
	
	List<Map> groupBy(String filed,String collectionName);
	
	void remove(List<Object> ids);
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.stereotype.Service;

import com.example.demo.bean.User;
import com.example.demo.service.UserService;

@Service
public class UserServiceImpl extends MongodbServiceImpl implements UserService{

	@Override
	public void update(User user) {
		super.updateByEntry(user);
	}
	
	@Override
	public Page<User> query(User user,Page<User> page) {
//		Page<?> pages = super.findAll(user, PageRequest.of(0, 2,Sort.by(Direction.DESC,"createTime","gender")));
		List<Order> orders=Arrays.asList(new Order(Direction.DESC,"createTime"),new Order(Direction.ASC,"gender"));
		Page<?> pages = super.findAll(user, PageRequest.of(0, 2,Sort.by(orders)));
		return (Page<User>) pages;
	}

	@Override
	public List<Map> groupBy(String filed,String collectionName){
		return super.groupBy(filed, collectionName);
	}

	@Override
	public void remove(List<Object> ids) {
		super.remove(ids, User.class);
	}
}

7,管道方法

①,unwind的用法

205412_cnxU_3574106.png

②,其余管道方法作用

205555_s8KM_3574106.png

8,mongodb的坑

切记,

①,mongodb不支持事务;

---这个真没办法了呀,能想到的办件就是手动恢复了,将有更新的原始记录保存起来,如果发生异常就是将原来的数据设置回去。

②,如果常对mongdb的一行的集合进行修改,切记用外键关联的方式,否则会造成锁表很严重

更多注意事项,请参考:

https://www.cnblogs.com/l1pe1/p/7871859.html

 

9,亲测mongodb事务支持情况

一旦异常抛出,下面方法就不会执行,也没有回滚

	@Transactional
	@Override
	public void transact() {
		User user=new User();
		user.setId("5b07fd0d75337d081c64c5e8");
		user.setName("红米1");
		super.updateByEntry(user);
		int i=9/0;
		System.out.println("====================");
		user=new User();
		user.setId("5b08bbef75337d0a58748083");
		user.setName("刘亦菲");
		super.updateByEntry(user);
	}
	
	@Transactional
	@Override
	public void repositoryTransact() {
		User user=new User();
		user.setName("红米NOTE4X");
		userRepsoitory.save(user);
		int i=9/0;
		System.out.println("====================");
		user=new User();
		user.setName("冬马");
		userRepsoitory.save(user);
	}

10,批量更新

db.employee.find().forEach(
    function(item){
        db.employee.update({_id:item._id},{$set:{email:'ai@qq.com'}})
    }
)

11,查询指定字段

        BasicDBObject fieldsObject=new BasicDBObject();
        fieldsObject.put("id","1");
        String queryJson="{\"_id\":\"5b36f44be664da37b4fafe9f\"}";
        String fieldJson="{\"_id\":\"1\",\"orderNo\":\"1\"}";
        BasicQuery query = new BasicQuery(queryJson,fieldJson);
        query.addCriteria(Criteria.where("id").in(orderRecordMap.keySet()));



        List<B2bOrder> orderList = mongoTemplate.find(query, B2bOrder.class);

12,java代码方式配置mongo

①,SpringBoot 没有提供 mongoxxxCustomizer,但springdata提供了一个AbstractMongoConfiguration

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;

import com.mongodb.MongoClient;

@Configuration
public class MongoConfig extends AbstractMongoConfiguration{

	@Override
	public MongoClient mongoClient() {
		return new MongoClient("127.0.0.1",27017);
	}

	@Override
	protected String getDatabaseName() {
		return "test";
	}

}

 

转载于:https://my.oschina.net/u/3574106/blog/1819088

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值