天天看點

第8章 MongoDB文檔資料庫MongoDB文檔資料庫

MongoDB文檔資料庫

1.MongoDB介紹

 對于那些需要緩存而且經常需要統計、分析和查詢的資料,對于Redis這樣簡單的NoSQL顯然不是很友善,而MongoDB對于那些需要統計、按條件查詢和分析的資料提供了支援,是一個最接近于關系資料庫的NoSQL。

 MongoDB是由C++編寫的一種NoSQL,是一個基于分布式檔案存儲的開源資料庫系統,在負載高時可以添加更多的節點以保證伺服器性能。MongoDB将資料存儲為一個文檔,資料結構由鍵值(key-value)對組成。

 與Redis一樣,我們先引入Spring Boot關于MongoDB的starter,同時推薦引入阿裡巴巴開發的fastjson開發包,友善JSON操作。代碼如下(Maven):

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.46</version>
</dependency>
           

接下來,配置MongoDB,在application.properties屬性檔案中添加如下代碼:

spring.data.mongodb.host=192.168.11.131     //MongoDB伺服器
spring.data.mongodb.username=spring          //MongoDB伺服器使用者名
spring.data.mongodb.password=123456
spring.data.mongodb.port=27017
spring.data.mongodb.database=springboot      //資料庫名稱

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

logging.level.root=INFO
           

2.使用MongoTemplate執行個體

Spring Data MongoDB主要是通過MongoTemplate進行操作資料,而Spring Boot會根據配置自動生成這個對象(不需要自己建立),下面通過執行個體說明如何通過MongoTemplate來操作資料。

首先建立一個使用者:

/**** imports ****/
// 辨別為MongoDB文檔
@Document
public class User implements Serializable {
	private static final long serialVersionUID = -7895435231819517614L;

	// MongoDB文檔編号,主鍵
	@Id
	private Long id;

	// 在MongoDB中使用user_name儲存屬性
	@Field("user_name")
	private String userName = null;

	private String note = null;

	// 角色清單
	private List<Role> roles = null;

/**** setter and getter ****/
}
           

文檔被辨別為@Docunment,說明它将作為MongoDB的文檔存在。注解@id則将對應的字段設為主鍵,使用@Field,這樣屬性userName與MongoDB中的user_name屬性對應起來了。這裡引入了角色清單,下面定義角色類:

/**** imports ****/
@Document
public class Role implements Serializable {
	private static final long serialVersionUID = -6843667995895038741L;
	private Long id;
	@Field("role_name")
	private String roleName = null;
	private String note = null;

	/**** setter and getter ****/
}
           

為了能夠測試,我們建立使用者測試器,代碼如下:

/**** imports ****/
@Controller
@RequestMapping("/user")
public class UserController  {
	
	// 後面會給出其操作的方法
	@Autowired
	private UserService userService = null;

	// 跳轉到測試頁面
	@RequestMapping("/page")
	public String page() {
		return "user";
	}
	
	/**
	 * 儲存(新增或者更新)使用者
	 * @param user -- 使用者
	 * @return 使用者資訊
	 */
	@RequestMapping("/save")
	@ResponseBody
	public User saveUser(@RequestBody User user) {
		userService.saveUser(user);
		return user;
	}
	
	/***
	 * 擷取使用者
	 * @param id -- 使用者主鍵
	 * @return 使用者資訊
	 */
	@RequestMapping("/get")
	@ResponseBody
	public User getUser(Long id) {
		User user = userService.getUser(id);
		return user;
	}
	
	
	/**
	 * 查詢使用者
	 * @param userName --使用者名稱
	 * @param note -- 備注
	 * @param skip -- 跳過使用者個數
	 * @param limit -- 限制傳回使用者個數
	 * @return
	 */
	@RequestMapping("/find")
	@ResponseBody
	public List<User> addUser(String userName, String note, Integer skip, Integer limit) {
		List<User> userList = userService.findUser(userName, note, skip, limit);
		return userList;
	}
	
	/**
	 * 更新使用者部分屬性
	 * @param id —— 使用者編号
	 * @param userName —— 使用者名稱
	 * @param note —— 備注
	 * @return 更新結果
	 */
	@RequestMapping("/update")
	@ResponseBody
	public UpdateResult updateUser(Long id, String userName, String note) {
		return userService.updateUser(id, userName, note);
	}
	
	/**
	 * 删除使用者
	 * @param id -- 使用者主鍵
	 * @return 删除結果
	 */
	@RequestMapping("/delete")
	@ResponseBody
	public DeleteResult deleteUser(Long id) {
		return userService.deleteUser(id);
	}
           

這裡引入UserService接口,先暫時不讨論它的實作,這裡的page方法會跳轉到一個測試的JSP頁面中,接下倆采用這個JSP進行一些測試:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello Spring Boot</title>
<script type="text/javascript"
	src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
<!--後面在此處加入JavaScript腳本-->
</script>
</head>
<body>
	<h1>操作MongoDB文檔</h1>
</body>
</html>
           

在後面的測試中,隻需在對應代碼處插入JS腳本就可以對背景發送HTTP的POST請求了。

3.使用MongoTemplate操作文檔

上述代碼使用了使用者服務接口(UserService),在它的接口設計裡包含了最常用的增删改查等功能,代碼如下:

package com.springboot.chapter8.service;

import java.util.List;

import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.springboot.chapter8.pojo.User;

public interface UserService {
	public void saveUser(User user);

	public DeleteResult deleteUser(Long id);

	public List<User> findUser(String userName, String note, int skip, int limit);

	public UpdateResult updateUser(Long id, String userName, String note);

	public User getUser(Long id);
}
           

下面看實作類,先來看查詢,包括擷取使用者(getUser方法)和查詢使用者(findUser方法):

@Service
public class UserServiceImpl implements UserService {

	// 注入MongoTemplate對象
	@Autowired
	private MongoTemplate mongoTmpl = null;

	@Override
	public User getUser(Long id) {
		return mongoTmpl.findById(id, User.class);
		// 如果隻需要擷取第一個也可以采用如下查詢方法
		// Criteria criteriaId = Criteria.where("id").is(id);
		// Query queryId = Query.query(criteriaId);
		// return mongoTmpl.findOne(queryId, User.class);
	}

	@Override
	public List<User> findUser(String userName, String note, int skip, int limit) {
		// 将使用者名稱和備注設定為模糊查詢準則
		Criteria criteria = Criteria.where("user_name").regex(userName).and("note").regex(note);
		// 建構查詢條件,并設定分頁跳過前skip個,至多傳回limit個
		Query query = Query.query(criteria).limit(limit).skip(skip);
		// 執行
		List<User> userList = mongoTmpl.find(query, User.class);
		return userList;
	}
           

其中的Criteria criteria = Criteria.where("user_name").regex(userName).and("note").regex(note);

這裡的where方法的參數設定為“userName”,這個字元串代表的是類User的屬性userName;regex方法代表的是正規表達式比對,即執行模糊查詢;and方法代表連接配接字,代表同時滿足。

啟動SpringBoot應用程式後,我們可以對findUser方法進行驗證,在浏覽器位址輸入http://localhost:8080/user/find?userName=user&note=note&skip=5&limit=5,可以看到結果。

接着是新增使用者資訊,代碼如下:

@Override
	public void saveUser(User user) {
		// 使用名稱為user文檔儲存使用者資訊
		mongoTmpl.save(user, "user");
		// 如果文檔采用類名首字元小寫,則可以這樣儲存
		// mongoTmpl.save(user);
	}
           

為了測試這個方法的結果,我們用之前定義的JS腳本進行驗證,代碼如下:

unction post(user) {
	var url = "./save"
	$.post({
		url : url,
		// 此處需要告知傳遞參數類型為JSON,不能缺少
		contentType : "application/json",
		// 将JSON轉化為字元串傳遞
		data : JSON.stringify(user),
		// 成功後的方法
		success : function(result, status) {
			if (result == null || result.id == null) {
				alert("插入失敗");
				return;
			}
		}
	});
}
for (var i = 1; i <= 10; i++) {
	var user = {
		'id' : i,
		'userName' : 'user_name_' + i,
		'note' : "note_" + i,
		'roles' : [ {
			'id' : i,
			'roleName' : 'role_' + i,
			'note' : 'note_' + i
		}, {
			'id' : i + 1,
			'roleName' : 'role_' + (i + 1),
			'note' : 'note_' + (i + 1)
		} ]
	};
	post(user);
}
           

通過它就能夠插入10條使用者資料,這裡可以看到使用者會多一個"_class"屬性,這個屬性儲存的是類的全限定名,通過它可以通過Java的反射機制生成對應的User。有時候我們可能需要删除或者更新,代碼如下:

@Override
	public DeleteResult deleteUser(Long id) {
		// 建構id相等的條件
		Criteria criteriaId = Criteria.where("id").is(id);
		// 查詢對象
		Query queryId = Query.query(criteriaId);
		// 删除使用者
		DeleteResult result = mongoTmpl.remove(queryId, User.class);
		return result;
	}

	@Override
	public UpdateResult updateUser(Long id, String userName, String note) {
		// 确定要更新的對象
		Criteria criteriaId = Criteria.where("id").is(id);
		Query query = Query.query(criteriaId);
		// 定義更新對象,後續可變化的字元串代表排除在外的屬性
		Update update = Update.update("user_name", userName);
		update.set("note", note);
		// 更新單個對象
		UpdateResult result = mongoTmpl.updateFirst(query, update, User.class);
		// 更新多個對象
		// UpdateResult result2 = mongoTmpl.updateMulti(query, update, User.class);
		return result;
	}
           

這裡與查詢一樣,使用主鍵建構了一個準則,然後使用remove方法将資料删除,執行删除後會傳回一個DeleteResult對象來記錄此次操作的結果。deleteCount代表删除文檔的條數。

在更新方法中,定義了一個更新對象(Update),在建立它的時候,使用構造方法設定了對使用者名的更新,然後使用set方法設定了note的更新,這樣表明我們隻是對這兩個屬性進行更新,其他屬性并不更新。

本節代碼已上傳Github: https://github.com/lizeyang18/SpringBoot-2.x/tree/master/chapter8

學習永不止步,繼續加油~

繼續閱讀