Java專案中MongoDb學習和使用總結

祖大帥發表於2019-04-12

最近在專案中使用MongoDb先簡單介紹MongoDb

MongoDb是什麼?

MongoDB是一個基於分散式檔案儲存的資料庫。由C++語言編寫。旨在為WEB應用提供可擴充套件的高效能資料儲存解決方案。
MongoDB 是一個介於關聯式資料庫和非關聯式資料庫之間的產品,是非關聯式資料庫當中功能最豐富,最像關聯式資料庫的。

幹什麼?

這個簡單,肯定是儲存資料。MongoDB 將資料儲存為一個文件,資料結構由鍵值(key=>value)對組成。MongoDB 文件類似於 JSON 物件。欄位值可以包含其他文件,陣列及文件陣列。

怎麼用?

mongoDb的基礎操作命令

自行百度吧。。。
mongoDb菜鳥教程

專案中如何進行MongoDb的CRUD

可以使用兩種方式MongoRepository方式和mongoTemplate方式

MongoRepository方式

  1. 這種方式只有查詢和新增,而且只需要建立倉庫繼承介面MongoRepository,按照規則建立方法就行。
public interface LogRepository extends MongoRepository<Log>{
    
}
複製程式碼

看一下MongoRepository原始碼裡有什麼方法

@NoRepositoryBean
public interface MongoRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    <S extends T> List<S> save(Iterable<S> var1);

    List<T> findAll();

    List<T> findAll(Sort var1);

    <S extends T> S insert(S var1);

    <S extends T> List<S> insert(Iterable<S> var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
複製程式碼
  1. 所以save和findAll可以直接使用,Sort為排序。如果想根據條件查詢的話可以按照規則輸入方法名。當需要根據實體類中的屬性查詢時,MongoRepository提供的方法已經不能滿足,我們需要在Repository倉庫中定義方法,定義方法名的規則為:find + By + 屬性名(首字母大寫),例如:
/**
	 * 根據地址查詢
	 * 
	 * @param address
	 * @author zyc
	 * @return 
	 */
	List<AlarmLog> findByAddress(String address);
	
    /**
     * 根據地址查詢帶分頁
     *
     * @param address
     * @author zyc
     * @return 
     */
	Page<AlarmLog> findByAddress(String address, Pageable pageable);
複製程式碼
  1. 當需要根據實體類中的屬性進行模糊查詢時,我們也需要在PersonRepository倉庫中定義方法,模糊查詢定義方法名的規則為:find + By + 屬性名(首字母大寫) + Like

	 /**
     * 根據地址查詢帶分頁
     *
     * @param address
     * @author zyc
     * @return 
     */
	Page<AlarmLog> findByAddressLike(String address, Pageable pageable);
複製程式碼
  1. 查詢指定的值在上面寫註解。其中value是查詢的條件,?0這個是佔位符,對應著方法中引數中的第一個引數,如果對應的是第二個引數則為?1。fields是我們指定的返回欄位,其中id是自動返回的,不用我們指定,json中{‘address’:1}的1代表true,也就是代表返回的意思。
@Query(value="{'address':?0}",fields="{'address':1}")
public Page<Person> findByAddressLike(String address,Pageable pageable);
複製程式碼

MongoTemplate方式

個人感覺這種方式更加全面一點,更好理解。

  1. pom引入mongoDB的依賴 pom.xml:
        <dependency> 
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-data-mongodb</artifactId>
	    </dependency>
複製程式碼
  1. 配置檔案配置連線 application.yml:
server: 
	  port: 8080
	spring:
	  data:
	    mongodb:
	      uri: mongodb://localhost:27017/test01
	  application:
	    name: myserver
複製程式碼
  1. 在需要向mongoDB CRUD時引入MongoTemplate
@Repository("userDao")
public class UserDaoImpl implements UserDao {

	/**
	 * 由springboot自動注入,預設配置會產生mongoTemplate這個bean
	 */
	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public void insert(User user) {
		//插入資料id自增(mongoDB中存在自己的_id,如果不自己定義自增,會預設返回mongoDB中的_id,我看網上說是不建議將_id自增的,因為高併發會影響效能。從這看的https://segmentfault.com/q/1010000006019599)
		mongoTemplate.insert(user);
	}

	@Override
	public void update(User user) {
		//根據id修改 update user set name=user.getName(),age=user.getAge() where id =user.getId()
		mongoTemplate.updateFirst(new Query(Criteria.where("id").is(user.getId())),
				new Update().set("name", user.getName()).set("age", user.getAge()), User.class);
	}

	@Override
	public List<User> findAll() {
		//select * from A
		return mongoTemplate.findAll(User.class);

	}

	@Override
	public User findOne() {
		//select * from A LIMIT 1
		return mongoTemplate.findOne(new Query(), User.class);// 第一條
	}

	@Override
	public User findById(Long id) {
		//Select * from A where a.id=id;
		return mongoTemplate.findById(id, User.class);// id查詢
	}

	@Override
	public List<User> find() {
		//select name from A where name='10'
		DBObject dbObject = new BasicDBObject();
		dbObject.put("name", "10"); // 查詢條件
		BasicDBObject fieldsObject = new BasicDBObject();
		// 指定返回的欄位
		fieldsObject.put("name", true);
		return mongoTemplate.find(new BasicQuery(dbObject, fieldsObject), User.class);
	}

	@Override
	public List<User> findOr() {
		//select * from A where name='10' or age=13
		return mongoTemplate.find(
				new Query(new Criteria().orOperator(Criteria.where("name").is("10"),Criteria.where("age").is(11))),
				User.class);
	}
	@Override
	public List<User> findAnd(){
		//select * from A where name='13' and id=1
		return mongoTemplate.find(new  Query(Criteria.where("name").is("13").and("id").is(1)), User.class);
	}
	@Override
	public List<User> findOrAnd() {
		//select * from A where a.id=1 and (age=9 or name =13)
		return mongoTemplate.find(
				new Query(Criteria.where("id").is(1).andOperator(new Criteria().orOperator(new Criteria().orOperator(Criteria.where("age").is(10),Criteria.where("name").is("13"))))),
				User.class);
	}
	@Override
	public List<User> findDayuXiaoyu(){
		//select * from A where  age>1 and age<10
		//gte大於等於 lte小於等於
		//ge大於 lt小於
		//ne 不等於
		Query ge_lt =  new Query(Criteria.where("age").gt(1).lt(10));//大於等於
		Query gte_lte =  new Query(Criteria.where("age").gte(1).lte(10));//小於等於
		Query ne =  new Query(Criteria.where("age").ne(5));//不等於
		return mongoTemplate.find(ne, User.class);
	}
	/**
	 * 模糊查詢  regex
			完全匹配  "^hzb$"
			右匹配    "^.*hzb$"
			左匹配    "^hzb.*$"
			雙開       "^.*hzb.*$"
	 */
	@Override
	public List<User> findLike(){
		Query query =  new Query(Criteria.where("name").regex("^.*2$"));
		return mongoTemplate.find(query, User.class);
	}
	@Override
	public List<User> findInNot(){
		//in 和not in
		Query in =  new Query(Criteria.where("age").in(5,6,7));
		//in
		Query notIn =  new Query(Criteria.where("age").nin(5,6,7));
		//not in
		return mongoTemplate.find(notIn, User.class);
	}
	@Override
	public List<User> findDie(){
		Query findDie =  new Query(Criteria.where("age").mod(9, 1));
		//取模(取餘) age % 5==1
		return mongoTemplate.find(findDie, User.class);
	}
	@Override
	public List<User> findAllMatching(){
		Query findAllMatching =  new Query(Criteria.where("list").all(1L,2L));
		//all 資料 [name=10, age=10, id=4, list=[1, 2]]
		//完全匹配返回資料
		return mongoTemplate.find(findAllMatching, User.class);
	}
	
	@Override
	public List<User> findSize(){
		Query findSize =  new Query(Criteria.where("list").size(2));
		//size 資料 [name=10, age=10, id=4, list=[1, 2]] 匹配陣列內的元素數量的 list.size =2 返回 
		return mongoTemplate.find(findSize, User.class);
	}
	@Override
	public List<User> findExists(){
		Query findExists =  new Query(Criteria.where("list").exists(false));
		//exists 判斷欄位是否為空  等同於sql的  list is null  和 list  is not null
		return mongoTemplate.find(findExists, User.class);
	}
	@Override
	public List<User> findType(){
		Query findType =  new Query(Criteria.where("list").type(4));
		//匹配資料型別
		//Double				1	“double”	
		//String				2	“string”	
		//Object				3	“object”	
		//Array	  			    4	“array”	
		//Binary data			5	“binData”	
		//Undefined				6	“undefined”	Deprecated.
		//ObjectId				7	“objectId”	
		//Boolean				8	“bool”	
		//Date	    			9	“date”	
		//Null	  				10	“null”	
		//Regular Expression	11	“regex”	
		//DBPointer				12	“dbPointer”	Deprecated.
		//JavaScript			13	“javascript”	
		//Symbol				14	“symbol”	Deprecated.
		//JavaScript (with scope)	15	“javascriptWithScope”	
		//32-bit integer		16	“int”	
		//Timestamp				17	“timestamp”	
		//64-bit integer		18	“long”	
		//Decimal128			19	“decimal”	New in version 3.4.
		//Min key				-1	“minKey”	
		//Max key				127	“maxKey”
		return mongoTemplate.find(findType, User.class);
	}
	@Override
	public List<User> findNot() {
		Query findDie =  new Query(Criteria.where("age").not().mod(9, 1));
		//not取反
		return mongoTemplate.find(findDie, User.class);
	}
	@Override
	public long count() {
		Query count =  new Query(Criteria.where("age").not().mod(9, 1));
		//總條數
		return mongoTemplate.count(count, User.class);
		
	}
	@Override
	public List<?> distinct(){
		return mongoTemplate.getCollection("User").distinct("name");
	}
	@Override
	public List<?> sort(){
		Query sort =  new Query();
		//排序
		return mongoTemplate.find(sort.with(new Sort(Direction.DESC, "id")), User.class);
	}
	@Override
	public List<?> limit(){
		Query limit =  new Query();
		//分頁
		//skip 設定起始數
		//limit 設定查詢條數
		return mongoTemplate.find(limit.skip(1).limit(3), User.class);
	}

}

複製程式碼

複雜分頁查詢 我的理解這裡的query就是用來封裝查詢條件的 criteria.and().is() 在這裡是構建了一個精準查詢的條件,並且用 'and' 相連。

@Override
    public Page<AlarmLog> findAlarmLog(LogCondition logCondition) {
        log.info("進入查詢告警介面,請求引數LogCondition={}",JSON.toJSONString(logCondition));
        int currentPage = logCondition.getCurrentPage();
        int pageSize = logCondition.getPageSize();
        Date startTime = logCondition.getStartTime();

        Query query = new Query();
        //設定起始數
        query.skip((currentPage - 1) * pageSize);
        //設定查詢條數
        query.limit(pageSize);
        Criteria criteria = new Criteria();
        if (StringUtils.isNotEmpty(logCondition.getSystem())) {
            criteria.and("system").is(logCondition.getSystem());
        }
        if (StringUtils.isNotEmpty(logCondition.getLevel())) {
            criteria.and("level").is(logCondition.getLevel());
        }
        if (StringUtils.isNotEmpty(logCondition.getHostname())) {
            criteria.and("hostname").is(logCondition.getHostname());
        }
        if (StringUtils.isNotEmpty(logCondition.getMessage())) {
            criteria.and("message").is(logCondition.getMessage());
        }
        if (StringUtils.isNotEmpty(logCondition.getStatus())) {
            criteria.and("status").is(logCondition.getStatus());
        }
        if (StringUtils.isNotEmpty(logCondition.getStartTime()) && StringUtils.isNotEmpty(logCondition.getEndTime())) {
            criteria.and("createTime").gte(logCondition.getStartTime()).lte(logCondition.getEndTime());
        } else if (StringUtils.isNotEmpty(logCondition.getStartTime())) {
            criteria.and("createTime").gte(logCondition.getStartTime());
        } else if (StringUtils.isNotEmpty(logCondition.getEndTime())) {
            criteria.and("createTime").lte(logCondition.getEndTime());
        }
        query.addCriteria(criteria);
        query.with(new Sort(Sort.Direction.DESC, "createTime"));
        List<AlarmLog> alarmLogs = mongoOperations.find(query,AlarmLog.class);
        log.info("查詢結果alarmLogs={}", JSON.toJSONString(alarmLogs));
        int count = (int) mongoOperations.count(query, AlarmLog.class);
        Page<AlarmLog> logPage = new Page<>();
        logPage.setRecords(alarmLogs);
        logPage.setTotal(count);
        logPage.setCurrent(currentPage);
        logPage.setSize(pageSize);
複製程式碼

這裡解釋一下,上面是最近做的一個查詢,是對多個欄位可能有可能沒有的分頁查詢,所以我只能用If做判斷處理,裡面有個查詢條件是個開始時間和截止時間內容。對一個欄位做兩次

criteria.and("createTime").gte()
criteria.and("createTime").lte()
複製程式碼

會報錯,所以使用了上面頗為醜陋的if else判斷。寫的時候查到了這種情況的處理方式,用到 andOperator 方法。試了一下可以。

//大於方法
Criteria gt = Criteria.where("createTime").gte("你的條件");
//小於方法
Criteria lt = Criteria.where("createTime").lte("你的條件");
/**
  * new Criteria().andOperator(gt,lt) 把上面的大於和小於放在一起,注意上面兩個key一定是一樣的
  * andOperator() 這個方法就是關鍵的方法了,把同key的多個條件組在一起
  * 但是 andOperator() 有個很坑的地方就是,在一個query中只能出現一次
  * 如果你有很固定很明確的入參,那還好,直接呼叫一次 andOperator()
  * 如果是多個key需要多個條件,而且條件數量還是動態的,怕不是魔鬼吧...
  */
criteria.andOperator(gte, lte);
複製程式碼

按照慣例推薦一個軟體:wox(解放你的桌面,和上次說的everything一起使用,爽到嗨。可以自己網上搜最新版)

連結:pan.baidu.com/s/1KDXwbQyk… 提取碼:48b6

相關文章