# MongoDB
## 數(shù)據(jù)庫分類
### 關(guān)系型數(shù)據(jù)庫
* 具備ACID特性
? ? * Atomic原子性刹缝,也就是說事務(wù)里的所有操作要么全部做完问慎,要么都不做惫叛,事務(wù)成功的條件是事務(wù)里的所有操作都成功奕锌,只要有一個(gè)操作失敗著觉,整個(gè)事務(wù)就失敗,需要回滾歇攻。*比如銀行轉(zhuǎn)賬固惯,從A賬戶轉(zhuǎn)100元至B賬戶梆造,分為兩個(gè)步驟:1)從A賬戶取100元缴守;2)存入100元至B賬戶。這兩步要么一起完成镇辉,要么一起不完成屡穗,如果只完成第一步,第二步失敗忽肛,錢會(huì)莫名其妙少了100元村砂。*
? ? * Consistency一致性,也就是說數(shù)據(jù)庫要一直處于一致的狀態(tài)屹逛,事務(wù)的運(yùn)行不會(huì)改變數(shù)據(jù)庫原本的一致性約束础废。*例如現(xiàn)有完整性約束a+b=10,如果一個(gè)事務(wù)改變了a罕模,那么必須得改變b评腺,使得事務(wù)結(jié)束后依然滿足a+b=10,否則事務(wù)*失敗淑掌。
? ? * Isolation獨(dú)立性蒿讥,所謂的獨(dú)立性是指并發(fā)的事務(wù)之間不會(huì)互相影響,如果一個(gè)事務(wù)要訪問的數(shù)據(jù)正在被另外一個(gè)事務(wù)修改抛腕,只要另外一個(gè)事務(wù)未提交芋绸,它所訪問的數(shù)據(jù)就不受未提交事務(wù)的影響。*比如現(xiàn)在有個(gè)交易是從A賬戶轉(zhuǎn)100元至B賬戶担敌,在這個(gè)交易還未完成的情況下摔敛,如果此時(shí)B查詢自己的賬戶,是看不到新增加的100元的全封。*
? ? * Durability持久性舷夺,持久性是指一旦事務(wù)提交后苦酱,它所做的修改將會(huì)永久的保存在數(shù)據(jù)庫上,即使出現(xiàn)宕機(jī)也不會(huì)丟失给猾。
* 局限性和不適用場景
? ? * 關(guān)系型數(shù)據(jù)庫為了維護(hù)一致性所付出的巨大代價(jià)就是其讀寫性能比較差疫萤。在網(wǎng)頁應(yīng)用中,尤其是SNS(社交)應(yīng)用中敢伸,一致性卻不是顯得那么重要扯饶,用戶A看到的內(nèi)容和用戶B看到同一用戶C內(nèi)容更新不一致是可以容忍的,或者說池颈,兩個(gè)人看到同一好友的數(shù)據(jù)更新的時(shí)間差那么幾秒是可以容忍的尾序,因此,關(guān)系型數(shù)據(jù)庫的最大特點(diǎn)在這里已經(jīng)無用武之地躯砰,起碼不是那么重要了每币。
? ? * 關(guān)系數(shù)據(jù)庫的另一個(gè)特點(diǎn)就是其具有固定的表結(jié)構(gòu),因此琢歇,其擴(kuò)展性比較差兰怠,而在SNS中,系統(tǒng)的升級(jí)李茫,功能的增加揭保,往往意味著數(shù)據(jù)結(jié)構(gòu)巨大變動(dòng),這一點(diǎn)關(guān)系型數(shù)據(jù)庫也難以應(yīng)付魄宏,需要新的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)秸侣。
### **非關(guān)系型數(shù)據(jù)庫 NoSQL(Not Only SQL )**
*? NoSQL數(shù)據(jù)庫的四大分類
|分類 |舉例 |典型應(yīng)用場景 |數(shù)據(jù)模型 |優(yōu)點(diǎn) |缺點(diǎn) |
|--- |--- |--- |--- |--- |--- |
|鍵值(key-value)存儲(chǔ)數(shù)據(jù)庫 |Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB |內(nèi)容緩存,主要用于處理大量數(shù)據(jù)的高訪問負(fù)載宠互,也用于一些日志系統(tǒng)等等味榛。 |Key 指向 Value 的鍵值對(duì),通常用hash table來實(shí)現(xiàn) |查找速度快 |數(shù)據(jù)無結(jié)構(gòu)化予跌,通常只被當(dāng)作字符串或者二進(jìn)制數(shù)據(jù) |
|--- |--- |--- |--- |--- |--- |
|**列存儲(chǔ)數(shù)據(jù)庫** |Cassandra, HBase, Riak |分布式的文件系統(tǒng) |以列簇式存儲(chǔ)搏色,將同一列數(shù)據(jù)存在一起 |查找速度快,可擴(kuò)展性強(qiáng)匕得,更容易進(jìn)行分布式擴(kuò)展 |功能相對(duì)局限 |
|**文檔型數(shù)據(jù)庫** |CouchDB, MongoDb |Web應(yīng)用(與Key-Value類似继榆,Value是結(jié)構(gòu)化的,不同的是數(shù)據(jù)庫能夠了解Value的內(nèi)容) |Key-Value對(duì)應(yīng)的鍵值對(duì)汁掠,Value為結(jié)構(gòu)化數(shù)據(jù) |數(shù)據(jù)結(jié)構(gòu)要求不嚴(yán)格略吨,表結(jié)構(gòu)可變,不需要像關(guān)系型數(shù)據(jù)庫一樣需要預(yù)先定義表結(jié)構(gòu) |查詢性能不高考阱,而且缺乏統(tǒng)一的查詢語法翠忠。 |
|**圖形(Graph)數(shù)據(jù)庫** |Neo4J, InfoGrid, Infinite Graph |社交網(wǎng)絡(luò),推薦系統(tǒng)等乞榨。專注于構(gòu)建關(guān)系圖譜 |圖結(jié)構(gòu) |利用圖結(jié)構(gòu)相關(guān)算法秽之。比如最短路徑尋址当娱,N度關(guān)系查找等 |很多時(shí)候需要對(duì)整個(gè)圖做計(jì)算才能得出需要的信息,而且這種結(jié)構(gòu)不太好做分布式的集群方案考榨。 |
* Mongodb
? ? * 是文檔型的非關(guān)系型數(shù)據(jù)庫跨细,使用bson( Binary Serialized Document Format) 結(jié)構(gòu)。其優(yōu)勢(shì)在于查詢功能比較強(qiáng)大河质,能存儲(chǔ)海量數(shù)據(jù)冀惭。
# Mac OSX 平臺(tái)安裝Mongo
## 使用 brew 下載并安裝
1、終端輸入:brew install mongodb
2掀鹅、安裝成功后可以看到提示:
```
To have launchd start mongodb now and restart at login:
? brew services start mongodb
Or, if you don't want/need a background service you can just run:
? mongod --config /usr/local/etc/mongod.conf
==> Summary
??? /usr/local/Cellar/mongodb/4.0.0: 18 files, 268.4MB
```
## 運(yùn)行mongoDB服務(wù)
1散休、首先創(chuàng)建一個(gè)數(shù)據(jù)庫存儲(chǔ)目錄 /data/db,命令行輸入:sudo mkdir -p /data/db
2乐尊、創(chuàng)建日志文件:sudo vim /data/db/mongo.log戚丸;創(chuàng)建pid文件:sudo vim /var/run/mongo.pid
3、啟動(dòng) mongodb扔嵌,分兩種啟動(dòng)方式:
* 啟動(dòng)命令直接指定命令參數(shù)方式:sudo mongod -port 27017 -dbpath /data/db -fork? -pidfilepath=/var/run/mongo.pid? -logpath /data/db/mongo.log
* 啟動(dòng)命令指定配置文件方式:
? ? * 1限府、創(chuàng)建配置文件 :sudo vim /etc/mongodb.conf?
? ? *? ? 2、執(zhí)行:sudo mongo -f /etc/mongodb.conf
* 啟動(dòng)參數(shù)說明(可以通過mongo -help來查看全部參數(shù)):
? ? * -port arg? ? #指定服務(wù)端口號(hào)对人,默認(rèn)端口27017谣殊。
? ? * -dbpath? ? #? 指定存儲(chǔ)路徑拂共。
? ? * -logpath arg? ? # 指定MongoDB日志文件牺弄,注意是指定文件不是目錄。使用fork參數(shù)時(shí)因?yàn)槿罩緹o法寫到控制臺(tái)宜狐,所以需要同時(shí)使用logpath參數(shù)势告。
? ? * -pidfilepath arg? ? # 指定PID File 的完整路徑,如果沒有設(shè)置抚恒,則沒有PID文件咱台。
? ? * -fork? ? # 以守護(hù)進(jìn)程的方式運(yùn)行MongoDB,相當(dāng)于nohup “shell”? &用法俭驮。使用fork參數(shù)時(shí)因?yàn)槿罩緹o法寫到控制臺(tái)回溺,所以需要同時(shí)使用logpath參數(shù)。
? ? * -directoryperdb? ? # 設(shè)置每個(gè)數(shù)據(jù)庫將被保存在一個(gè)單獨(dú)的目錄
? ? * -maxConns arg? # 最大同時(shí)連接數(shù) 默認(rèn)2000
? ? * -auth? ? #用戶認(rèn)證混萝,默認(rèn)false遗遵,當(dāng)設(shè)置為true時(shí)候,進(jìn)入數(shù)據(jù)庫需要auth驗(yàn)證逸嘀,當(dāng)數(shù)據(jù)庫里沒有用戶车要,則不需要驗(yàn)證也可以操作。直到創(chuàng)建了第一個(gè)用戶崭倘,之后操作都需要驗(yàn)證翼岁。
啟動(dòng)成功后可以看到以下提示:
```
[initandlisten] waiting for connections on port 27017
或
forked process: 41540
child process started successfully, parent exiting
```
## 停止mongoDB服務(wù)
正常關(guān)閉方式:
* 前臺(tái)方式啟動(dòng)時(shí)类垫,命令行光標(biāo)鍵入CTRL+C
* 通過連接的客戶端關(guān)閉,首先連接mongo成功后
? ? * 第一步:use admin
? ? * 第二步:db.shutdownServer()
異常關(guān)閉再次啟動(dòng)報(bào)錯(cuò)時(shí):
* 使用kill進(jìn)程方式
? ? * ps -ef |grep mongo
? ? * kill -15 pid? ? #建議不要使用 ”kill -9 pid“琅坡,因?yàn)槿绻\(yùn)行在沒開啟日志(—journal)的情況下悉患,可能會(huì)造成數(shù)據(jù)損失。
> 注意:在mongodb的啟動(dòng)時(shí)榆俺,在數(shù)據(jù)目錄下购撼,會(huì)生成一個(gè)mongod.lock文件。如果在正常退出時(shí)谴仙,會(huì)清除這個(gè)mongod.lock文件迂求,若是異常退出,在下次啟動(dòng)的時(shí)候晃跺,會(huì)禁止啟動(dòng)揩局,并看到下面的報(bào)錯(cuò)。
```
? ? exception in initAndListen: DBPathInUse: Unable to lock the lock file:
? ? /data/db/mongod.lock (Resource temporarily unavailable). Another mongod instance is already running on the /data/db directory, terminating
```
## Mongo連接
### 客戶端連接
語法格式:mongo 遠(yuǎn)程主機(jī)ip或DNS:端口號(hào)/數(shù)據(jù)庫名 -u user -p password
例:連接本地?cái)?shù)據(jù)庫掀虎,在終端窗口輸入:mongo
```
~ ? mongo
MongoDB shell version v4.0.0
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 4.0.0
```
例:連接遠(yuǎn)程sit環(huán)境mongo數(shù)據(jù)庫
```
~ ? mongo 10.4.12.78/admin -u sit-user -p xxxxA5
MongoDB shell version v4.0.0
connecting to: mongodb://10.4.12.78:27017/admin
MongoDB server version: 3.2.12
```
### 標(biāo)準(zhǔn)uri連接
語法格式:mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
```
`#!/usr/bin/env python
``# -*- coding:utf-8 -*-
from pymongo import MongoClient
uri = 'mongodb://sit-user:xxxxqA5@10.4.12.78/admin'
con = MongoClient(uri)`
```
# MongoDB語法
## 概念術(shù)語
|SQL術(shù)語/概念 |MongoDB術(shù)語/概念 |解釋/說明 |
|--- |--- |--- |
|database |database |數(shù)據(jù)庫 |
|--- |--- |--- |
|table |collection |數(shù)據(jù)庫表/集合 |
|row |document |數(shù)據(jù)記錄行/文檔 |
|column |field |數(shù)據(jù)字段 |
|index |index |索引 |
|primary key |primary key |主鍵,MongoDB自動(dòng)將_id字段設(shè)置為主鍵 |
## 數(shù)據(jù)庫操作
### 創(chuàng)建數(shù)據(jù)庫
1凌盯、語法格式:use <database_name>? ? #如果數(shù)據(jù)庫存在時(shí)會(huì)切換到該數(shù)據(jù)庫,不存在時(shí)會(huì)創(chuàng)建該數(shù)據(jù)庫烹玉。
2驰怎、操作成功后可以看到提示:
```
> use sms
switched to db sms
```
### 刪除數(shù)據(jù)庫
1、語法格式:db.dropDatabase()? ? #刪除當(dāng)前使用的數(shù)據(jù)庫二打,可以通過命令“db”來查看當(dāng)前數(shù)據(jù)庫
2县忌、操作成功后可以看到提示:
```
> db? ? #查看當(dāng)前數(shù)據(jù)庫
sms
> db.dropDatabase()
{ "ok" : 1 }
```
## 集合操作
### 創(chuàng)建集合
1、語法格式:db.createCollection(<name>,{ <options>})? ? #name為要?jiǎng)?chuàng)建的集合名继效,options為可選參數(shù):
* capped? ? #布爾類型症杏,如果為 true,則創(chuàng)建固定集合瑞信。固定集合是指有著固定大小的集合厉颤,當(dāng)達(dá)到最大值時(shí),它會(huì)自動(dòng)覆蓋最早的文檔凡简。當(dāng)該值為 true 時(shí)逼友,必須指定 size 參數(shù)。
* size? ? #數(shù)值秤涩,為固定集合指定一個(gè)最大值(以字節(jié)計(jì))帜乞。如果 capped 為 true,也需要指定該字段**溉仑。**
* max? ? #數(shù)值挖函,指定固定集合中包含文檔的最大數(shù)量。
2、執(zhí)行:db.createCollection("seller",{ capped : true, size :6142800, max : 10000 }怨喘,創(chuàng)建集合成功后可以看到提示:
```
> db? ? #查看當(dāng)前數(shù)據(jù)庫
sms
> db.createCollection("seller",{ capped : true, size :6142800, max : 10000 })
{ "ok" : 1 }
```
### 刪除集合
1津畸、語法格式:db.collection_name.drop()
2、刪除集合成功后必怜,可以看到命令行返回“true”肉拓,否則返回“false”。
```
> show collections? ? #查看當(dāng)前數(shù)據(jù)庫下的集合
ark_open_api_account
seller
> db.ark_open_api_account.drop()
true
> show collections
seller
```
## 文檔操作
### 創(chuàng)建文檔
1梳庆、語法格式:db.collection_name.insert(<document>)
2暖途、執(zhí)行db.seller.insert({"role" : "partner","shopname" : "redqa009-測試","email" : "[xx@163.com](mailto:xx@163.com)"})?
```
> db.seller.insert({"role" : "partner","shopname" : "redqa009-測試","email" : "[xx@163.com](mailto:xx@163.com)"})
WriteResult({ "nInserted" : 1 })
> db.seller.find()? ? #查詢文檔
{ "_id" : ObjectId("5b554bd275f30ccd39ca6483"), "role" : "partner", "shopname" : "redqa009-測試", "email" : "xx@163.com" }
```
或? 先定義document后再執(zhí)行insert(document)
```
> document=([{"role" : "partner","shopname" : "redqa007品牌店","email" : "1401261542@qq.com"},{"role" : "partner","shopname" : "redqa018","email" : "qatest6@redqa.xyz"}])
[
{
"role" : "partner",
"shopname" : "redqa007品牌店",
"email" : "1401261542@qq.com"
},
{
"role" : "partner",
"shopname" : "redqa018",
"email" : "[qatest6@redqa.xyz](mailto:qatest6@redqa.xyz)"
}
]
> db.seller.insert(document)
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
> db.seller.find()
{ "_id" : ObjectId("5b554bd275f30ccd39ca6483"), "role" : "partner", "shopname" : "redqa009-測試", "email" : "[xx@163.com](mailto:xx@163.com)" }
{ "_id" : ObjectId("5b554ee875f30ccd39ca6484"), "role" : "partner", "shopname" : "redqa007品牌店", "email" : "xx@qq.com" }
{ "_id" : ObjectId("5b554ee875f30ccd39ca6485"), "role" : "partner", "shopname" : "redqa018","email" : "xxx@redqa.xyz" }
```
### 更新文檔
* update()方法
? ? * 1、語法格式:
```
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,? # 可選膏执,含義為如果不存在update的記錄驻售,是否插入objNew,true為插入,默認(rèn)是false更米,不插入欺栗。
multi: <boolean>,? # 可選,默認(rèn)是false,只更新找到的第一條記錄征峦,如果這個(gè)參數(shù)為true,就把按條件查出來多條記錄全部更新迟几。
writeConcern: <document>? # writeConcern** **:可選,拋出異常的級(jí)別栏笆。
}
)
```
? ? * 2类腮、更新shopname為"redqa009-測試1”商家的郵箱
? ? * 執(zhí)行'db.seller.update({shopname:"redqa009-測試1"},{$set:{email:"xx@163.com"}},{upsert:true})'
```
> db.seller.find()
{ "_id" : ObjectId("5b554bd275f30ccd39ca6483"), "role" : "partner", "shopname" : "redqa009-測試", "email" : "lxx@163.com" }
{ "_id" : ObjectId("5b554ee875f30ccd39ca6484"), "role" : "partner", "shopname" : "redqa007品牌店", "email" : "xx@qq.com" }
{ "_id" : ObjectId("5b554ee875f30ccd39ca6485"), "role" : "partner", "shopname" : "redqa018", "email" : "xx@redqa.xyz" }
> db.seller.update({shopname:"redqa009-測試1"},{$set:{email:"xx@163.com"}},{upsert:true})
WriteResult({
? ? "nMatched" : 0,
? ? "nUpserted" : 1,
? ? "nModified" : 0,
? ? "_id" : ObjectId("5b556dca30563a38f0284e00")
})
```
> 注意:當(dāng)集合為Capped collection時(shí),如果更新或替換操作更改了文檔大小蛉加,則操作將失敗蚜枢。錯(cuò)誤提示如下:
```
WriteResult({
? ? "nMatched" : 0,
? ? "nUpserted" : 0,
? ? "nModified" : 0,
? ? "writeError" : {
? ? ? ? "code" : 10003,
? ? ? ? "errmsg" : "Cannot change the size of a document in a capped collection: 79 != 77"
? ? }
})
```
* save()方法
? ? * 1、語法格式
```
db.collection.save(
? <document>,? ? # 根據(jù)文檔中的'_id'字段七婴,找到一個(gè)已經(jīng)存在的文檔祟偷,進(jìn)行更新察滑。
? {
? ? writeConcern: <document>
? }
)
```
> 補(bǔ)充:
> 當(dāng)文檔中包含'_id'字段打厘,但匹配不到已存在的文檔,也會(huì)將文檔插入數(shù)據(jù)庫贺辰。
> 當(dāng)文檔中不含'_id'字段户盯,save方法將調(diào)用insert方法,插入這條文檔并分配一個(gè)_id饲化。
### 刪除文檔
1莽鸭、語法格式:
```
db.collection.remove(
? <query>,? ? # 可選,刪除的文檔的條件。
? {
? ? justOne: <boolean>,? ? # 可選,如果設(shè)為 true 或 1吃靠,則只刪除一個(gè)文檔硫眨。
? ? writeConcern: <document>
? }
)
```
> 注意:Capped collection不允許使用remove()方法刪除,只能使用db.collection.drop()方法刪除集合巢块。db.collection.isCapped() 命令可以查看一個(gè)集合是否是 Capped Collection礁阁。
### 查詢文檔
```
1巧号、db.collection.find(query, projection) # 可選,query為查詢條件姥闭,可選丹鸿,projection指定返回的鍵。
```
### 比較操作符
* 大于:$gt
* 大于等于:$gte
* 小于:$lt
* 小于等于:$lte
* 等于:$eq
例:查詢訂單“total_discounted_price”大于等于100并且小于等于200的任意一個(gè)訂單號(hào)棚品。
```
db.order.findOne({total_discounted_price:{$gte:150,$lte:200}},{order_id:1})
#projection:1代表只返回指定字段靠欢,為0代表不返回該字段。
```
* 不等于:$ne
例:查詢商家("seller":"53df5710b4c4d6383ae8e9a6")任意一個(gè)不是“已取消”的訂單
```
db.order_package.find({"seller":"53df5710b4c4d6383ae8e9a6","status":{$ne:998}})
```
* 匹配數(shù)組中任意值:$in
例:查詢所有訂單狀態(tài)狀態(tài)為“待配貨”铜跑、“配貨中”或“已發(fā)貨”的訂單门怪。
```
db.order_package.find({ "status": {$in:[4,5,6]}})
```
* 不匹配數(shù)組中任意值:$nin
### 邏輯操作符
* 與查詢:$and
例:查詢商家("seller":"53df5710b4c4d6383ae8e9a6")所有訂單狀態(tài)狀態(tài)為“待配貨”、“配貨中”或“已發(fā)貨”的訂單锅纺。
```
db.order_package.find({$and:[{"seller":"53df5710b4c4d6383ae8e9a6"},{"status": {$in:[4,5,6]}}]})
等同于
db.order_package.find({ "seller":"53df5710b4c4d6383ae8e9a6","status": {$in:[4,5,6]}})
```
* 或查詢:$or
例:查詢訂單“total_discounted_price”小于等于100或大于等于200的訂單號(hào)薪缆。
```
db.order.find({$or:[{total_discounted_price:{$lte:100}},{total_discounted_price:{$gte:200}}]})
```
### 元素操作符
* 查詢是否存在某字段:$exists
例:查詢維護(hù)了貿(mào)易模式的所有商家。
```
db.seller.find({ "trade_mode":{$exists:true} })
```
*? 查詢數(shù)組中元素是否滿足指定的條件:$elemMatch
例:查詢所有支持“red_bonded”物流模式的商家伞广。
```
被查詢集合的數(shù)據(jù)結(jié)構(gòu):
{
? "_id": ObjectId("5a151d9deb90b912e76ee832"),
? "shopname": "redqa009-測試",
? "logistics_infos": [
? ? {
? ? ? "name": "red_auto",
? ? ? "logistics": "auto",
? ? ? "is_default": true
? ? },
? ? {
? ? ? "name": "red_bonded",
? ? ? "logistics": "bonded",
? ? ? "customs_code": "SHANGHAI",
? ? ? "is_default": false
? ? }
? ],
? "trade_mode": 0
}
寫法:
db.seller.find({ "logistics_infos":{$elemMatch:{name:"red_bonded"}} })
```
### 排序
* 升序
```
db.COLLECTION_NAME.find().sort({KEY:1})
```
* 降序
```
db.COLLECTION_NAME.find().sort({KEY:-1})
```
# MongoDB訪問權(quán)限控制
## 訪問控制參數(shù)
### **綁定IP地址**
* mongod 啟動(dòng)參數(shù):-bind_ip? <ip_address>?
默認(rèn)值是所有的IP地址都能訪問拣帽,該參數(shù)指定MongoDB對(duì)外提供服務(wù)的綁定IP地址,用于監(jiān)聽客戶端 Application的連接嚼锄,客戶端只能使用綁定的IP地址才能訪問mongod减拭,其他IP地址是無法訪問的。
### **設(shè)置監(jiān)聽端口**
* mongod 啟動(dòng)參數(shù):-port <port>? ?
MongoDB 默認(rèn)監(jiān)聽的端口是27017区丑,該參數(shù)顯式指定MongoDB實(shí)例監(jiān)聽的TCP 端口拧粪,只有當(dāng)客戶端Application連接的端口和MongoDB實(shí)例監(jiān)聽的端口一致時(shí),才能連接到MongoDB實(shí)例沧侥。
### **啟用用戶驗(yàn)證**
* mongod 啟動(dòng)參數(shù):-auth?
當(dāng)mongod 使用該參數(shù)啟動(dòng)時(shí)可霎,MongoDB會(huì)驗(yàn)證客戶端連接的賬戶和密碼,以確定其是否有訪問的權(quán)限宴杀。如果認(rèn)證不通過癣朗,那么客戶端不能訪問MongoDB的數(shù)據(jù)庫。
### **權(quán)限認(rèn)證**
* mongo 連接參數(shù):-username <username>, -u <username>
* mongo 連接參數(shù):-password <password>, -p <password>
* mongo 連接參數(shù):-authenticationDatabase <dbname> 指定創(chuàng)建User的數(shù)據(jù)庫旺罢;在特定的數(shù)據(jù)庫中創(chuàng)建User旷余,該DB就是User的authentication database。
在連接mongo時(shí)扁达,使用參數(shù) --authenticationDatabase正卧,會(huì)認(rèn)證 -u 和 -p 參數(shù)指定的賬戶和密碼。如果沒有指定驗(yàn)證數(shù)據(jù)庫跪解,mongo使用連接字符串中指定的DB作為驗(yàn)證數(shù)據(jù)塊炉旷。
```
mongo 10.4.12.78/admin -u sit-user -p xxxx4qA5 --authenticationDatabase "admin"
```
## **基于角色的訪問控制**
**內(nèi)置角色**
內(nèi)置角色是MongoDB預(yù)定義的角色,操作的資源是在DB級(jí)別上。MongoDB擁有一個(gè)SuperUser的角色:root窘行,擁有最大權(quán)限骏啰,能夠在系統(tǒng)的所有資源上執(zhí)行任意操作。
* 數(shù)據(jù)庫內(nèi)置用戶角色
? ? * read:授予User只讀數(shù)據(jù)的權(quán)限
? ? * readWrite:授予User讀寫數(shù)據(jù)的權(quán)限
* 數(shù)據(jù)庫內(nèi)置管理角色
? ? * dbAdmin:在當(dāng)前dB中執(zhí)行管理操作
? ? * dbOwner:在當(dāng)前DB中執(zhí)行任意操作
? ? * userAdmin:在當(dāng)前DB中管理User
* 所有數(shù)據(jù)庫角色
? ? * readAnyDatabase
? ? * readWriteAnyDatabase
? ? * userAdminAnyDatabase
? ? * dbAdminAnyDatabase
* 超級(jí)用戶角色
? ? * root
### 用戶創(chuàng)建
```
>? db.createUser({user: "jhh",pwd: "pwd",roles: [{role:"readWrite",db:"sms"}]})
Successfully added user: {
? ? "user" : "jhh",
? ? "roles" : [
? ? ? ? {
? ? ? ? ? ? "role" : "readWrite",
? ? ? ? ? ? "db" : "sms"
? ? ? ? }
? ? ]
}
```
> 補(bǔ)充:查看用戶授權(quán)情況可以在admin庫下通過db.system.users.find({user:"user_name"})查看抽高。
### **用戶的作用范圍**
在admin 數(shù)據(jù)庫中創(chuàng)建的角色判耕,作用范圍是全局的,能夠在admin翘骂,其他數(shù)據(jù)庫中使用壁熄,并且能夠繼承其他數(shù)據(jù)庫的角色;而在非admin中創(chuàng)建的角色碳竟,作用范圍是當(dāng)前數(shù)據(jù)庫草丧,只能在當(dāng)前DB中使用,只能繼承當(dāng)前數(shù)據(jù)庫的角色莹桅。
# MongoDB備份與恢復(fù)
MongoDB官方提供了兩套數(shù)據(jù)導(dǎo)入導(dǎo)出工具:一般來說昌执,進(jìn)行整庫導(dǎo)出導(dǎo)入時(shí)使用mongodump和mongostore,這一對(duì)組合操作的數(shù)據(jù)是BSON格式诈泼,進(jìn)行大量dump和restore時(shí)效率較高懂拾。進(jìn)行單個(gè)集合導(dǎo)出導(dǎo)入時(shí)使用mongoexport和mongoimport,這一對(duì)組合操作的數(shù)據(jù)是JSON格式铐达,可讀性較高岖赋。
## 數(shù)據(jù)庫備份與恢復(fù)
* mongodump腳本語法:mongodump -h dbhost -d dbname -o dbdirectory
? ? * -h:
? ? ? ? MongDB所在服務(wù)器地址,例如:127.0.0.1瓮孙,當(dāng)然也可以指定端口號(hào):127.0.0.1:27017
? ? * -d:
? ? ? ? 需要備份的數(shù)據(jù)庫實(shí)例唐断,例如:test
? ? * -o**:**
? ? ? ? 備份的數(shù)據(jù)存放位置,例如:\data\dump杭抠,當(dāng)然該目錄需要提前建立脸甘,在備份完成后,系統(tǒng)自動(dòng)在dump目錄下建立一個(gè)test目錄偏灿,這個(gè)目錄里面存放該數(shù)據(jù)庫實(shí)例的備份數(shù)據(jù)丹诀。
* mongorestore腳本語法:mongorestore -h <hostname><:port> -d dbname <path>
? ? * --host <:port>, -h <:port>:
? ? ? ? MongoDB所在服務(wù)器地址,默認(rèn)為: localhost:27017
? ? * --db , -d :
? ? ? ? 需要恢復(fù)的數(shù)據(jù)庫實(shí)例菩混,例如:test忿墅,當(dāng)然這個(gè)名稱也可以和備份時(shí)候的不一樣,比如test2
? ? * --drop:
? ? ? ? 恢復(fù)的時(shí)候沮峡,先刪除當(dāng)前數(shù)據(jù),然后恢復(fù)備份的數(shù)據(jù)亿柑。
? ? * <path>:
? ? ? ? mongorestore 最后的一個(gè)參數(shù)邢疙,設(shè)置備份數(shù)據(jù)所在位置,例如:\data\dump\test。
? ? ? ? 你不能同時(shí)指定 <path> 和 --dir 選項(xiàng)疟游,--dir也可以設(shè)置備份目錄呼畸。
? ? * --dir:
? ? ? ? 指定備份的目錄
? ? ? ? 你不能同時(shí)指定 <path> 和 --dir 選項(xiàng)。
## 集合導(dǎo)入與導(dǎo)出
* mongoexport語法:mongoexport -d dbname -c collectionname -o file --type json/csv -f field
? ? * -h:代表遠(yuǎn)程連接的數(shù)據(jù)庫地址颁虐,默認(rèn)連接本地Mongo數(shù)據(jù)庫
? ? * --port:代表遠(yuǎn)程連接的數(shù)據(jù)庫的端口蛮原,默認(rèn)連接的遠(yuǎn)程端口27017
? ? * -d :數(shù)據(jù)庫名
? ? *? -c :collection名
? ? *? -o :輸出的文件名,導(dǎo)出成功后文件會(huì)生成在當(dāng)前執(zhí)行路徑下另绩。
? ? *? --type : 輸出的格式儒陨,默認(rèn)為json
? ? *? -f :輸出的字段,如果-type為csv笋籽,則需要加上-f "字段名"蹦漠。
? ? * -q:代表查詢條件
? ? * -limit:讀取指定數(shù)量的數(shù)據(jù)記錄
例:從sit環(huán)境數(shù)據(jù)數(shù)據(jù)庫導(dǎo)出sms庫里seller集合任意5文檔到本地。
```
~ ? mongoexport -h=10.4.12.78 -d=sms -c=seller -o=seller.json
--limit=5 -u sit-user -p cDk%KVJA4qA5 --authenticationDatabase=admin --query '{logistics:"auto"}'
2018-07-24T12:50:18.992+0800 connected to: 10.4.12.78
2018-07-24T12:50:19.037+0800 exported 5 records
```
> 注意:這里一定要加—authenticationDatabase=admin指定use和password作為admin庫的驗(yàn)證车海,順序直接跟在-u和-p參數(shù)之后笛园,否則會(huì)作為 sms庫的驗(yàn)證,導(dǎo)致驗(yàn)證失斒讨ァ(猜測sit-user是admin庫下全局用戶研铆,在sms的庫用戶中不存在)。具體見“角色作用范圍”一節(jié)州叠。
* mongoimport語法:mongoimport -d dbname -c collectionname --file filename --headerline --type json/csv -f field
? ? *? -d :數(shù)據(jù)庫名
? ? *? -c :collection名
? ? *? --type :導(dǎo)入的格式默認(rèn)json
? ? *? -f :導(dǎo)入的字段名,type為json格式時(shí)不能指定蚜印。
? ? *? --headerline :如果導(dǎo)入的格式是csv,則可以使用第一行的標(biāo)題作為導(dǎo)入的字段
? ? *? --file :要導(dǎo)入的文件
例:將上面導(dǎo)出的seller.json文件導(dǎo)入到本地?cái)?shù)據(jù)庫sms下留量。
```
~ ? mongoimport -d sms? -c seller --file seller.json --type json
2018-07-24T13:39:05.380+0800? ? connected to: localhost
2018-07-24T13:39:05.394+0800? ? imported 5 documents
```
客戶端查看seller集合文檔條數(shù):
```
導(dǎo)入執(zhí)行前:
> db.seller.find().count();
2
導(dǎo)入執(zhí)行后:
> db.seller.find().count();
7
```
# 數(shù)據(jù)庫與緩存之間更新機(jī)制
## **緩存同步的常用模式**
緩存同步的模式窄赋,可以按照緩存的用途(主要用于讀或者寫)分為兩類:讀緩存的同步和寫緩存的同步。
讀緩存的同步:
### **緩存預(yù)加載模式**
提前將數(shù)據(jù)從數(shù)據(jù)庫加載到緩存楼熄,如果數(shù)據(jù)庫有寫更新忆绰,同步更新緩存。
### **緩存直讀模式**
應(yīng)用先查看緩存中是否有該數(shù)據(jù)可岂,有則直接使用错敢,如果沒有,從數(shù)據(jù)庫加載缕粹,然后放入緩存稚茅,下次以后再訪問就可以直接從緩存中獲得。
### **緩存直寫模式**
在數(shù)據(jù)更新時(shí)平斩,同時(shí)寫入緩存和數(shù)據(jù)庫亚享。這種模式是最穩(wěn)妥的辦法,但是性能會(huì)受到一定的影響绘面。
其中的過程是這樣的:
1.檢查用戶請(qǐng)求的數(shù)據(jù)是緩存中是否有存在欺税,如果有存在的話侈沪,只需要直接把請(qǐng)求的數(shù)據(jù)返回,無需查詢數(shù)據(jù)庫晚凿。
2.如果請(qǐng)求的數(shù)據(jù)在緩存中找不到亭罪,這時(shí)候再去查詢數(shù)據(jù)庫。返回請(qǐng)求數(shù)據(jù)的同時(shí)歼秽,把數(shù)據(jù)存儲(chǔ)到緩存中一份应役。
3.保持緩存的“新鮮性”,每當(dāng)數(shù)據(jù)發(fā)生變化的時(shí)候(比如燥筷,數(shù)據(jù)有被修改箩祥,或被刪除的情況下),要同步的更新緩存信息荆责,確保用戶不會(huì)在緩存取到舊的數(shù)據(jù)滥比。