一:MongoDB 概述
1、NoSQL 簡介linux
1. 概念:NoSQL(Not Only SQL的縮寫),指的是非關係型數據庫,是對不一樣於傳統的關係型數據庫的數據庫管理系統的統稱。用於超大規模數據的存儲,數據存儲不須要固定的模式,無需多餘操做就能夠橫向擴展。算法
2. 特色sql
1. 優勢:具備高可擴展性、分佈式計算、低成本、架構靈活且是半結構化數據,沒有複雜的關係等。mongodb
2. 缺點:沒有標準化、有限的查詢功能、最終一致是不直觀的程序等。shell
3. 分類數據庫
4. NoSQL 和 RDBMS 的對比json
2、MongoDB 簡介數組
1. 概念:MongoDB 是由C++語言編寫的一個基於分佈式文件存儲的開源文檔型數據庫系統。緩存
2. 功能:JSON 文檔模型、動態的數據模式、二級索引強大、查詢功能、自動分片、水平擴展、自動複製、高可用、文本搜索、企業級安全、聚合框架MapReduce、大文件存儲GridFS。安全
1. 面向集合文檔的存儲:適合存儲Bson(json的擴展)形式的數據;
2. 格式自由,數據格式不固定,生產環境下修改結構均可以不影響程序運行;
3. 強大的查詢語句,面向對象的查詢語言,基本覆蓋sql語言全部能力;
4. 完整的索引支持,支持查詢計劃;
5. 使用分片集羣提高系統擴展性;
3. 適用場景
1. 網站數據:Mongo很是適合實時的插入,更新與查詢,並具有網站實時數據存儲所需的複製及高度伸縮性。
2. 緩存:因爲性能很高,Mongo也適合做爲信息基礎設施的緩存層。在系統重啓以後,由Mongo搭建的持久化緩存層能夠避免下層的數據源 過載。
3. 在高伸縮性的場景,用於對象及JSON數據的存儲。
4. 數據類型
3、概念詳解
1. 數據庫:MongoDB 默認的數據庫爲"db",該數據庫存儲在data目錄中。單個實例能夠容納多個獨立的數據庫,每個都有本身的集合和權限,不一樣的數據庫也放置在不一樣的文件中。
2. 集合:集合就是 MongoDB 文檔組,相似於 RDBMS 的表格。集合存在於數據庫中,集合沒有固定的結構,這意味着你在對集合能夠插入不一樣格式和類型的數據,但一般狀況下咱們插入集合的數據都會有必定的關聯性。
3. 文檔:一個鍵值(key-value)對(即BSON)。MongoDB 的文檔不須要設置相同的字段,而且相同的字段不須要相同的數據類型,這與關係型數據庫有很大的區別,也是 MongoDB 很是突出的特色。
4、安裝配置
1. Windows
1. 下載(4.2.7版本以上)並直接安裝
2. 配置環境變量
3. 測試
=
2. Linux
1 # 解壓到指定目錄 2 tar -zxvf mongodb-linux-x86_64-rhel70-4.2.7.tgz -C /opt/ 3 4 # 配置環境變量 5 # MONGODB_HOME 6 export MONGODB_HOME=/opt/mongodb-linux-x86_64-rhel70-4.2.7 7 export PATH=$PATH:$MONGODB_HOME/bin 8 9 # 測試 10 [root@controller ~]# mongo 11 MongoDB shell version: 4.2.7 12 connecting to: test
二:MongoDB CLI
1、增刪改
2、操做符
3、查詢
1. 基本操做
2. 聚合查詢
3. 管道操做:MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理
5、管理
6、索引和高可用
1. 索引
簡介 做用:索引一般可以極大的提升查詢的效率,若是沒有索引,MongoDB在讀取數據時必須掃描集合中的每一個文件並選取那些符合查詢條件的記錄。索引主要用於排序和檢索。 MongoDB使用 ensureIndex() 方法來建立索引,ensureIndex()方法基本語法格式以下所示: db.collection.createIndex(keys, options) 語法中 Key 值爲要建立的索引字段,1爲指定按升序建立索引,若是你想按降序來建立索引指定爲-1,也能夠指定爲hashed(哈希索引)。 索引屬性: background:是否後臺構建索引,在生產環境中,若是數據量太大,構建索引可能會消耗很長時間,爲了避免影響業務,能夠加上此參數,後臺運行同時還會爲其餘讀寫操做讓路,這個建議配置爲true開啓,這樣來提升效率。 unique:是否爲惟一索引 索引類型: 單鍵索引: 在某一個特定的屬性上創建索引,例如:db.users. createIndex({age:-1}); 1,mongoDB在ID上創建了惟一的單鍵索引,因此常常會使用id來進行查詢; 2,在索引字段上進行精確匹配、排序以及範圍查找都會使用此索引; 複合索引: 在多個特定的屬性上創建索引,例如:db.users. createIndex({username:1,age:-1,country:1}); 1,複合索引鍵的排序順序,能夠肯定該索引是否能夠支持排序操做; 2,在索引字段上進行精確匹配、排序以及範圍查找都會使用此索引,但與索引的順序有關; 3,爲了性能考慮,應刪除存在與第一個鍵相同的單鍵索引 多鍵索引: 在數組的屬性上創建索引,例如:db.users. createIndex({favorites.city:1}); 哈希索引: 不一樣於傳統的B-樹索引,哈希索引使用hash函數來建立索引。 1,在索引字段上進行精確匹配,但不支持範圍查詢,不支持多鍵hash; 2,Hash索引上的入口是均勻分佈的,在分片集合中很是有用; 優化 1,開啓內置的查詢分析器,記錄讀寫操做效率: db.setProfilingLevel(n,{m}),n的取值可選0,1,2; 0是默認值表示不記錄; 1表示記錄慢速操做,若是值爲1,m必須賦值單位爲ms,用於定義慢速查詢時間的閾值; 2表示記錄全部的讀寫操做; 2,分析慢速查詢 就是查看執行計劃,使用explain分析慢速查詢。 explain的入參可選值爲: "queryPlanner":是默認值,表示僅僅展現執行計劃信息; "executionStats":表示展現執行計劃信息同時展現被選中的執行計劃的執行狀況信息; "allPlansExecution":表示展現執行計劃信息,並展現被選中的執行計劃的執行狀況信息,還展現備選的執行計劃的執行狀況信息 3,合理創建索引 創建索引的規則: 1,索引頗有用,可是它也是有成本的——它佔內存,讓寫入變慢; 2,mongoDB一般在一次查詢裏使用一個索引,因此多個字段的查詢或者排序須要複合索引才能更加高效; 3,複合索引的順序很是重要,例如此腳本所示: 4,在生成環境構建索引每每開銷很大,時間也不能夠接受,在數據量龐大以前儘可能進行查詢優化和構建索引; 5,避免昂貴的查詢,使用查詢分析器記錄那些開銷很大的查詢便於問題排查; 6,經過減小掃描文檔數量來優化查詢,使用explain對開銷大的查詢進行分析並優化; 7,索引是用來查詢小範圍數據的,不適合使用索引的狀況: 1,每次查詢都須要返回大部分數據的文檔,避免使用索引 2,寫比讀多 優化目標: 1,根據需求創建索引 2,每一個查詢都要使用索引以提升查詢效率, winningPlan. stage 必須爲IXSCAN ; 3,追求totalDocsExamined = nReturned
2. 高可用
1,可複製集 可複製集是跨多個MongDB服務器(節點)分佈和維護數據的方法。mongoDB能夠把數據從一個節點複製到其餘節點並在修改時進行同步,集羣中的節點配置爲自動同步數據;舊方法叫作主從複製,mongoDB 3.0之後推薦使用可複製集; 做用: 1,避免數據丟失,保障數據安全,提升系統安全性; (最少3節點,最大50節點) 2,自動化災備機制,主節點宕機後經過選舉產生新主機;提升系統健壯性; (7個選舉節點上限) 3,讀寫分離,負載均衡,提升系統性能; 4,生產環境推薦的部署模式; 原理: 數據同步:從節點與主節點保持長輪詢;1.從節點查詢本機oplog最新時間戳;2.查詢主節點oplog晚於此時間戳的全部文檔;3.加載這些文檔,並根據log執行寫操做; 阻塞複製:與writeconcern相關,不須要同步到從節點的策略(如: acknowledged Unacknowledged 、w1),數據同步都是異步的,其餘狀況都是同步; 心跳機制:成員之間會每2s 進行一次心跳檢測(ping操做),發現故障後進行選舉和故障轉移; 選舉制度:主節點故障後,其他節點根據優先級和bully算法選舉出新的主節點,在選出主節點以前,集羣服務是隻讀的; 注意: MongoDB複製集裏Primary節點是不固定的,因此生產環境千萬不要直連Primary。 2,分片集羣 分片是把大型數據集進行分區成更小的可管理的片,這些數據片分散到不一樣的mongoDB節點,這些節點組成了分片集羣。 做用: 1,數據海量增加,須要更大的讀寫吞吐量:存儲分佈式 2,單臺服務器內存、cpu等資源是有瓶頸的:負載分佈式 注意:分片集羣是個雙刃劍,在提升系統可擴展性和性能的同時,增大了系統的複雜性,因此在實施以前請肯定是必須的。 容易發生的情況: 請求分流:經過路由節點將請求分發到對應的分片和塊中; 數據分流:內部提供平衡器保證數據的均勻分佈,數據平均分佈式請求平均分佈的前提; 塊的拆分:3.4版本塊的最大容量爲64M或者10w的數據,當到達這個閾值,觸發塊的拆分,一分爲二; 塊的遷移:爲保證數據在分片節點服務器分片節點服務器均勻分佈,塊會在節點之間遷移。通常相差8個分塊的時候觸發; 分片注意點: 熱點 :某些分片鍵會致使全部的讀或者寫請求都操做在單個數據塊或者分片上,致使單個分片服務器嚴重不堪重負。自增加的分片鍵容易致使寫熱點問題; 不可分割數據塊:過於粗粒度的分片鍵可能致使許多文檔使用相同的分片鍵,這意味着這些文檔不能被分割爲多個數據塊,限制了mongoDB均勻分佈數據的能力; 查詢障礙:分片鍵與查詢沒有關聯,形成糟糕的查詢性能。 建議: 1,不要使用自增加的字段做爲分片鍵,避免熱點問題; 2,不能使用粗粒度的分片鍵,避免數據塊沒法分割; 3,不能使用徹底隨機的分片鍵值,形成查詢性能低下; 4,使用與經常使用查詢相關的字段做爲分片鍵,並且包含惟一字段(如業務主鍵,id等); 5,索引對於分區一樣重要,每一個分片集合上要有一樣的索引,分片鍵默認成爲索引;分片集合只容許在id和分片鍵上建立惟一索引;
三:MongoDB API
1、客戶端鏈接
1 public class MongoDBClient { 2 public static Logger logger = Logger.getLogger(MongoDBClient.class.getName()); 3 protected static MongoClient mongoClient; 4 5 /** 6 * 封裝MongoDB鏈接 7 * 8 * @param driver 遠程鏈接URL 9 * @param database 數據庫 10 * @param collection 集合 11 * @return 12 */ 13 public synchronized static MongoCollection<Document> getMongoClient(String driver, String database, 14 String collection) { 15 if (mongoClient == null) { 16 // 鏈接到MongoDB客戶端 17 mongoClient = MongoClients.create(driver); 18 if (mongoClient != null) { 19 logger.info("mongoClient init success!"); 20 // 鏈接指定數據庫 21 MongoDatabase db = mongoClient.getDatabase(database); 22 if (database != null) { 23 logger.info("正在使用" + database + "數據庫"); 24 // 鏈接到指定集合 25 return db.getCollection(collection); 26 } 27 } else { 28 logger.info("mongoClient init failed!"); 29 } 30 } 31 return null; 32 } 33 }
2、增刪改
1 public class MongoDBClient { 2 /** 3 * 插入文檔 4 */ 5 @Test 6 public void insert() { 7 MongoCollection<Document> collection = getMongoClient("mongodb://admin:000000@localhost:27017", 8 "studentmanager", "info"); 9 /** 10 * 插入一條 11 */ 12 // 追加插入一條 13 collection.insertOne(new Document("name", "zhangsan").append("age", 18).append("gneder", "男")); 14 15 // 插入json數據 16 String json = "{" + "'name':'lisi'" + "'age':'20'" + "'gender':'女'" + "}"; 17 collection.insertOne(Document.parse(json)); 18 19 /** 20 * 插入多條 21 */ 22 List<Document> documents = new ArrayList<Document>(); 23 for (int i = 0; i < 4; i++) { 24 documents.add(new Document("i", i)); 25 } 26 collection.insertMany(documents); 27 } 28 29 /** 30 * 修改文檔 31 */ 32 @Test 33 public void update() { 34 MongoCollection<Document> collection = getMongoClient("mongodb://admin:000000@localhost:27017", 35 "studentmanager", "info"); 36 37 // 修改一條 38 collection.updateOne(new Document("name", "zhangsan"), new Document("$set", new Document("age", 20))); 39 40 // 修改多條 41 collection.updateMany(new Document("i", new Document("$lt", 2)), 42 new Document("$set", new Document("name", "wangwu").append("age", 10))); 43 } 44 45 /** 46 * 刪除文檔 47 */ 48 @Test 49 public void delete() { 50 MongoCollection<Document> collection = getMongoClient("mongodb://admin:000000@localhost:27017", 51 "studentmanager", "info"); 52 53 // 刪除一條 54 collection.deleteOne(new Document("name", "zhangsan")); 55 56 // 刪除多條 57 collection.deleteMany(new Document("i", new Document("$gte", 2))); 58 } 59 }
3、查詢
1 public class MongoDBClient { 2 /** 3 * 查詢全部 4 */ 5 @Test 6 public void findAll() { 7 MongoCollection<Document> collection = getMongoClient("mongodb://admin:000000@localhost:27017", 8 "studentmanager", "info"); 9 // 獲取迭代器 10 FindIterable<Document> find = collection.find(); 11 // 獲取遊標 12 MongoCursor<Document> iterator = find.iterator(); 13 // 經過遊標遍歷檢索爲文檔集合 14 while (iterator.hasNext()) { 15 System.out.println(iterator.next()); 16 } 17 } 18 19 /** 20 * 條件查詢 21 */ 22 @Test 23 public void findByConditions() { 24 MongoCollection<Document> collection = getMongoClient("mongodb://admin:000000@localhost:27017", 25 "studentmanager", "info"); 26 // 範圍查詢 27 // where gender = 男 28 collection.find(Filters.eq("gender", "男")); 29 // where age=10,age=18,age=20 30 collection.find(Filters.in("age", 10, 18, 20)); 31 32 // 邏輯查詢 33 // where age >= 16 and age <= 20 34 collection.find(Filters.and(Filters.gte("age", 16), Filters.lte("age", 20))); 35 // where age > 20 or age < 16 36 collection.find(Filters.or(Filters.gt("age", 20), Filters.lt("age", 16))); 37 38 // 類型查詢 39 collection.find(Filters.type("name", "string")); 40 41 // 模糊查詢:name中是以zhang開頭的 42 FindIterable<Document> find = collection.find(Filters.regex("name", "zhang*")); 43 MongoCursor<Document> iterator = find.iterator(); 44 while (iterator.hasNext()) { 45 Document document = iterator.next(); 46 System.out.println(document.get("name")); 47 } 48 } 49 50 /** 51 * 排序和分頁 52 */ 53 @Test 54 public void sortAndLimit() { 55 MongoCollection<Document> collection = getMongoClient("mongodb://admin:000000@localhost:27017", 56 "studentmanager", "info"); 57 58 /** 59 * 排序 60 */ 61 // 升序排序:where gender="男" order by age asc 62 collection.find(Filters.eq("gender", "男")).sort(Sorts.ascending("age")); 63 // 降序排序:where gender="男" order by age desc 64 collection.find(Filters.eq("gender", "男")).sort(Sorts.descending("age")); 65 // 多條件排序:where gender="男" order by age asc and score desc 66 collection.find(Filters.eq("gender", "男")) 67 .sort(Sorts.orderBy(Sorts.ascending("age"), Sorts.descending("score"))); 68 69 /** 70 * 分頁 71 */ 72 FindIterable<Document> skip = collection.find(Filters.gt("age", 16)).limit(3).skip(2); 73 MongoCursor<Document> iterator = skip.iterator(); 74 while (iterator.hasNext()) { 75 System.out.println(iterator.next()); 76 } 77 } 78 }