SpringBoot整合mongodb

mongodb做爲文檔型數據庫,是最像關係型數據庫的。javascript

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的用法

②,其他管道方法做用

8,mongodb的坑

切記,html

①,mongodb不支持事務;java

---這個真沒辦法了呀,能想到的辦件就是手動恢復了,將有更新的原始記錄保存起來,若是發生異常就是將原來的數據設置回去。程序員

②,若是常對mongdb的一行的集合進行修改,切記用外鍵關聯的方式,不然會形成鎖表很嚴重web

更多注意事項,請參考:spring

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

 

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提供了一個AbstractMongoConfigurationapp

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";
	}

}
相關文章
相關標籤/搜索