一、介紹 在介紹 MongoDB 之前,我先介紹一下業務開發的時候遇到的痛點,以便大家對它有一個更加清晰的認識! 最近在用資料庫存儲數據的時候發現這麼一個坑,例如從消息隊列中監聽消息的時候,原來的做法是將監聽的消息數據存儲在資料庫,以便好對異常消息數據進行追溯,消息內容使用text類型存儲,起初因為 ...
一、介紹
在介紹 MongoDB 之前,我先介紹一下業務開發的時候遇到的痛點,以便大家對它有一個更加清晰的認識!
最近在用資料庫存儲數據的時候發現這麼一個坑,例如從消息隊列中監聽消息的時候,原來的做法是將監聽的消息數據存儲在資料庫,以便好對異常消息數據進行追溯,消息內容使用text
類型存儲,起初因為數據內容很短,沒啥毛病,但是當隨著業務的擴展,收到的消息內容越來越長,最後發現資料庫中的text
欄位類型無法很好的支持查詢,於是在這個時候,就開始考慮採用更加合適的資料庫來存儲這種消息數據!
在經過一番討論之後,對於這種 json 類型的消息數據的存儲,大家一致認為採用 MongoDB 是最佳的選擇!
據官方介紹,MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富、最像關係資料庫的一款高性能的 NoSQL 資料庫。
MongoDB 將數據存儲為一個文檔,數據結構由鍵值(key=>value
)對組成。
其中的文檔類似於 JSON 對象。欄位值可以包含其他文檔、數組及文檔數組,數據結構的支持非常靈活!
的確,在使用的過程當中,正如所介紹的,數據的存儲和查詢,性能極快,而且很好的滿足我們的需求!
話不多說,下麵我們就一起來瞭解一下,這款資料庫應該如何使用!
二、環境配置
在學習它之前,我們需要先搭建好環境,MongoDB 的安裝也非常簡單!
2.1、Windows 平臺
如果你是 Windows 平臺,MongoDB 提供了可用於 32 位和 64 位系統的預編譯二進位,安裝基本是傻瓜式的操作,登錄 MongoDB 官網並且下載安裝包,然後一步一步的操作即可!
2.2、Linux 平臺
生產環境基本都是 Linux 平臺,為了和生產保持一致,小編採用的伺服器是CentOS7
,安裝過程也比較簡單!
- 創建資源文件
sudo vim /etc/yum.repos.d/mongodb-org-4.0.repo
- 編輯內容如下
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
- 運行以下命令安裝 mongodb
sudo yum install -y mongodb-org
- 安裝完成之後,配置
mongod.conf
允許遠程連接
#編輯mongod.conf
vim /etc/mongod.conf
#將net:bindIp: 127.0.0.1 改為 0.0.0.0
net:
bindIp:0.0.0.0
- 最後啟動服務
#開啟服務
systemctl start mongod
#其他服務
#關閉服務
systemctl stop mongod
#重啟服務
systemctl restart mongod
#開機自啟
systemctl enable mongod
至此,環境配置已經完成!
三、資料庫操作
MongoDB 的數據操作,是開發人員接觸最頻繁的部分,第一次使用的時候,你會發現它和我們傳統使用的 sql 腳本命令完全不同,但是又類似,下麵我們就一起來深入的瞭解下!
3.1、進入 MongoDB
進入 MongoDB 服務很簡單,輸入如下命令即可進入!
mongo
例如,在CentOS
裡面輸入命令之後,進入的服務界面如下:
3.2、創建資料庫
MongoDB 創建資料庫的語法格式如下:
use DATABASE_NAME
如果資料庫不存在,則創建資料庫,否則切換到指定資料庫。
輸入如下命令,可以查詢資料庫列表
#查詢資料庫列表
show dbs
#命令輸出結果:
admin
config
local
可以看到,當前 MongoDB 有三個資料庫!
輸入如下命令,可以切換到admin
資料庫
use admin
輸入db
命令,還可以查詢當前資料庫
db
3.3、創建用戶
預設的情況下,是沒有用戶的,也無法操作資料庫,因此我們需要創建一個用戶,同時給他分配許可權!
3.3.1、創建一個管理員用戶
創建一個用戶、密碼都是admin
的用戶,同時給這個用戶分配userAdminAnyDatabase
角色,指定的資料庫為admin
!
#創建一個admin用戶
db.createUser(
{
user: "admin",
pwd: "admin",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
})
其中欄位含義如下:
- user:用戶的名字;
- pwd:用戶的密碼;
- roles:指定用戶的角色,可以用一個空數組給新用戶設定空角色。
- roles 中的 role:指定角色。
- roles 中的 db:指定的資料庫,例如上面中的角色
userAdminAnyDatabase
,只在 admin 資料庫中可用。
角色在 MongoDB 中,代表著某個用戶是否有許可權訪問資料庫或者操作資料庫,理解這點非常重要!
MongoDB 角色定義如下:
角色類型 | 名稱 | 描述 |
---|---|---|
admin資料庫角色 | readAnyDatabase | 只在admin資料庫中可用,賦予用戶所有資料庫的讀許可權 |
admin資料庫角色 | readWriteAnyDatabase | 只在admin資料庫中可用,賦予用戶所有資料庫的讀寫許可權 |
admin資料庫角色 | userAdminAnyDatabase | 只在admin資料庫中可用,賦予用戶所有資料庫的userAdmin許可權 |
admin資料庫角色 | dbAdminAnyDatabase | 只在admin資料庫中可用,賦予用戶所有資料庫的dbAdmin許可權 |
admin資料庫角色 | clusterAdmin | 只在admin資料庫中可用,賦予用戶所有分片和複製集相關函數的管理許可權 |
admin資料庫角色 | root | 只在admin資料庫中可用,超級賬號,超級許可權 |
資料庫管理角色 | dbAdmin | 允許用戶在指定資料庫中執行管理函數,如索引創建、刪除,查看統計或訪問system.profile |
資料庫管理角色 | userAdmin | 允許用戶向system.users集合寫入,可以在指定資料庫里創建、刪除和管理用戶 |
資料庫用戶角色 | read | 允許用戶讀取指定資料庫 |
資料庫用戶角色 | readWrite | 允許用戶讀寫指定資料庫 |
3.3.2、創建一個不受訪問限制的超級用戶
如果你想創建一個不受訪問限制的超級用戶,賦予root
角色即可!
#創建超級用戶
db.createUser(
{
user:"root",
pwd:"root",
roles:["root"]
}
)
3.3.3、創建一個業務資料庫普通用戶
如果你想創建一個業務資料庫普通用戶,例如只能訪問test_db
資料庫,並且只負責數據的増查改刪。
# 創建或者切換資料庫到test_db
use test_db
# 創建一個test用戶,並且只能訪問test_db,對錶只有讀寫許可權
db.createUser(
{
user: "test",
pwd: "test",
roles: [ { role: "readWrite", db: "test_db" } ]
})
3.3.4、驗證用戶是否可以正常登錄
對於剛剛創建的用戶,我們怎麼驗證它是否能正常登錄呢?命令也很簡單!
db.auth("test","test")
如果返回是1
表示鑒權正常!
3.3.5、查詢當前資料庫用戶信息
查詢創建的用戶,命令也很簡單!
# 查看創建的用戶
show users
3.3.6、修改用戶密碼
有些時候,我們會忘記密碼,可通過如下方式進行修改!
#修改用戶密碼
db.changeUserPassword("username", "xxxxx")
3.3.7、刪除用戶
如果某個用戶需要停用,可通過如下方式進行刪除
#切換指定資料庫
use test_db
#刪除用戶
db.dropUser('test')
3.3.8、刪除資料庫
如果某個資料庫需要停用,可通過如下方式進行刪除(只有超級管理員有許可權刪除)
#切換指定資料庫
use test_db
#刪除資料庫
db.dropDatabase()
3.4、創建集合
MongoDB 並無表這個概念,而對應的定義叫:集合,我們在關係型資料庫中看到的表數據,在 MongoDB 中被定義為:文檔,MongoDB 也被很多人成為文檔資料庫!
在關係型資料庫中,表數據是一行一行的存儲,但是在 MongoDB 中,可能不是這樣,如果你存儲的 json 非常複雜,嵌套很深,那麼在 MongoDB 中存儲的行數,可能非常深,存儲的時候類似我們在頁面看到的父子表結構!
3.4.1、創建一個集合
MongoDB 中使用 createCollection() 方法來創建集合。
語法格式:
db.createCollection(name, options)
參數說明:
- name: 要創建的集合名稱
- options: 可選參數, 指定有關記憶體大小及索引的選項
例如,在 test_db 資料庫中創建 tb_user 集合:
# 切換到test_db資料庫
use test_db
# 創建 tb_user 集合
db.createCollection("tb_user")
#輸出結果
{ "ok" : 1 }
如果要查看已有的集合,可以使用show collections
命令!
show collections
下麵是帶有幾個關鍵參數的createCollection()
的用法,下麵命令表示:創建固定集合tb_user
,整個集合空間大小6142800
KB, 文檔最大個數為10000
個
db.createCollection("tb_user", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } )
在 MongoDB 中,很多時候不需要手動創建集合。當你插入一個文檔時,MongoDB 會自動創建集合!
# 向集合tb_user 插入一條文檔數據
db.tb_user.insert({"name" : "張三"})
#查詢集合
show collections
# 輸出結果
tb_user
3.4.2、刪除一個集合
MongoDB 中使用 drop() 方法來刪除集合。
語法格式:
db.collection.drop()
例如,刪除在 test_db 資料庫中 tb_user 集合:
# 切換到test_db資料庫
use test_db
# 創建 tb_user 集合
db.tb_user.drop()
#輸出結果
true
3.4、創建文檔
創建文檔,類似我們在關係型資料庫中,將數據插入到資料庫,操作也很簡單!
3.4.1、插入文檔
MongoDB 使用 insert()
或 save()
方法向集合中插入文檔。
語法如下:
db.COLLECTION_NAME.insert(document)
或
db.COLLECTION_NAME.save(document)
save()
:如果_id
主鍵存在則更新數據,如果不存在就插入數據。insert()
:若插入的數據主鍵已經存在,則會拋異常,提示主鍵重覆,不保存當前數據。
例如,在test_db
資料庫的tb_user
集合中,插入一條數據
db.tb_user.insert(
{
name:"張三",
age:18,
gender:"男",
tags: ['宅男', '技術控', '脫髮嚴重']
})
如果該集合不在該資料庫中, MongoDB 會自動創建該集合併插入文檔。
查看已插入文檔,命令如下:
#查詢tb_user集合中的數據
db.tb_user.find()
# 輸出結果
{ "_id" : ObjectId("6022310f6b5e964b0a5916e6"), "name" : "張三", "age" : 18, "gender" : "男", "tags" : [ "宅男", "技術控", "脫髮嚴重" ] }
當然,你還可以通過save()
命令進行插入,如果不指定_id
欄位 save()
方法類似於 insert()
方法。如果指定 _id
欄位,則會更新該 _id
的數據。
例如,將張三
年齡更新到30
歲!
db.tb_user.save(
{
_id: ObjectId("6022310f6b5e964b0a5916e6"),
name:"張三",
age:30,
gender:"男",
tags: ['宅男', '技術控', '脫髮嚴重']
})
查看文檔
db.tb_user.find()
# 輸出結果
{ "_id" : ObjectId("6022310f6b5e964b0a5916e6"), "name" : "張三", "age" : 30, "gender" : "男", "tags" : [ "宅男", "技術控", "脫髮嚴重" ] }
3.4.2、更新文檔
MongoDB 提供了 update()
和 save()
方法來更新集合中的文檔。
語法格式如下:
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
- query : update的查詢條件,類似sql update查詢內where後面的。
- update : update的對象和一些更新的操作符(如$,$inc...)等,也可以理解為sql update查詢內set後面的
- upsert : 可選,這個參數的意思是,如果不存在update的記錄,是否插入objNew,true為插入,預設是false,不插入
- multi : 可選,mongodb 預設是false,只更新找到的第一條記錄,如果這個參數為true,就把按條件查出來多條記錄全部更新。
- writeConcern :可選,拋出異常的級別。
例如,將張三
年齡更新到22
歲!
db.tb_user.update({'name':'張三'},{$set:{'age':22}})
查詢已更新的數據
db.tb_user.find()
# 輸出結果
{ "_id" : ObjectId("602235216b5e964b0a5916e8"), "name" : "張三", "age" : 22, "gender" : "男", "tags" : [ "宅男", "技術控", "脫髮嚴重" ] }
以上語句只會修改第一條發現的文檔,如果你要修改多條相同的文檔,則需要設置multi
參數為true
。
db.tb_user.update({'name':'張三'},{$set:{'age':22}},{multi:true})
3.4.3、刪除文檔
MongoDB 中的remove()
函數是用來移除集合中的數據
語法格式如下:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
- query :(可選)刪除的文檔的條件。
- justOne : (可選)如果設為 true 或 1,則只刪除一個文檔,如果不設置該參數,或使用預設值 false,則刪除所有匹配條件的文檔。
- writeConcern :(可選)拋出異常的級別。
例如,刪除姓名為張三
的用戶
db.tb_user.remove({'name':'張三'})
查詢數據是否被刪除
db.col.find()
#結果為空
3.4.4、查詢文檔
MongoDB 查詢文檔使用 find() 方法。
語法格式如下:
db.collection.find(query, projection)
- query :可選,使用查詢操作符指定查詢條件
- projection :可選,使用投影操作符指定返回的鍵。查詢時返迴文檔中所有鍵值, 只需省略該參數即可(預設省略)。
如果你需要以易讀的方式來讀取數據,可以使用 pretty() 方法,語法格式如下:
db.col.find().pretty()
首先我們插入幾條數據,插入結果如下:
例如,查詢一個性別為男
的用戶信息
#單個條件查詢,類似 sql語句中的 gender = '男'
db.tb_user.find({"gender":"男"})
查詢一個性別為男
,姓名為張三
的用戶
#多條件查詢,類似 sql語句中的 gender = '男' and name = '李四'
db.tb_user.find({"gender":"男","name":"李四"})
查詢一個性別為男
或者 姓名為張三
的用戶
#多條件查詢,類似 sql語句中的 gender = '男' or name = '李四'
db.tb_user.find({$or:[{"gender":"男"},{"name": "李四"}]})
查詢一個性別為男
或者 姓名為張三
,同時年齡大於30
的用戶
#多條件查詢,類似 sql語句中的 age > 30 and ( gender = '男' or name = '李四')
db.tb_user.find({"age": {$gt:30}, $or:[{"gender":"男"},{"name": "李四"}]})
3.4.5、分頁查詢文檔
如果需要分頁查詢集合數據,可以使用limit()
和skip()
函數,其中limit()
表示讀幾條數據,skip()
表示從第幾條數據開始。
#從集合中的第三行數據開始,讀2條數據返回
db.tb_user.find({}).limit(2).skip(3)
3.4.6、文檔排序
和關係型資料庫一樣,MongoDB 可以使用sort()
方法進行排序,通過參數指定排序的欄位,並使用 1
和 -1
來指定排序的方式,其中 1
為升序排列,而 -1
是用於降序排列。
例如,查詢tb_user
文檔,按照age
進行升序排序!
db.tb_user.find({}).sort({"age":1})
3.5、創建索引
索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB 在讀取數據時必須掃描集合中的每個文件並選取那些符合查詢條件的記錄。
這種掃描全集合的查詢效率是非常低的,特別在處理大量的數據時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常致命的。
3.5.1、創建索引
MongoDB 使用 createIndex()
方法來創建索引,語法格式如下:
db.collection.createIndex(keys, options)
語法中 Key 值為你要創建的索引欄位,1
為指定按升序創建索引,如果你想按降序來創建索引指定為 -1
即可!
例如,給tb_user
文檔中的age
創建一個索引!
db.tb_user.createIndex({"age":1})
創建索引是一個比較耗時的動作,我們還可以通過參數配置,在後臺創建索引。
db.tb_user.createIndex({"age":1}, {background: true})
通過在創建索引時加background:true
的選項,讓創建工作在後臺執行!
3.5.2、查看索引
MongoDB 提供了getIndexes()
方法,可以進行查看索引。
例如,查詢tb_user
集合中的索引
db.tb_user.getIndexes()
3.5.3、刪除索引
不在需要的索引,我們可以將其刪除。刪除索引時,可以刪除集合中的某一索引,可以刪除全部索引。
語法格式:
db.COLLECTION_NAME.dropIndex("INDEX-NAME")
例如,刪除集合tb_user
集合中的age
索引:
#查詢索引
db.tb_user.getIndexes()
#輸出結果
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test_db.tb_user"
},
{
"v" : 2,
"key" : {
"age" : 1
},
"name" : "age_1",
"ns" : "test_db.tb_user"
}
]
刪除對應的age_1
索引!
db.tb_user.dropIndex("age_1")
四、客戶端
對於任何一款資料庫,如果沒有可視化界面操作,在開發的時候,可以說極其不方便,下麵推薦一款小編經常使用的一款客戶端。
- Robo 3T(免費、輕量級) ,可以訪問官網獲取
- Studio 3T(全面,收費),訪問官網地址獲取
其中小編採用的是第二款,整體的體驗比Robo 3T
要一點,兩者功能都比較齊全!
在使用的時候,可以根據個人喜愛進行選擇!
五、重要的一步
網上發現很多 mongodb 被黑,使大家將目光投向了mongodb 的許可權控制。
其實 mongodb 本身有一套完備的 RBAC 許可權控制體系,這次被黑基本都是沒有遵照 mongodb 的生產環境部署手冊部署的結果。
我們平時玩一玩 mongodb 習慣了不設置用戶名密碼,當我們的資料庫放到公網時,由於我們也沒有設置用戶名密碼,任何人都可以隨便訪問,而且由於我們沒有開啟授權訪問,使得任何登錄到 mongodb 伺服器的用戶都擁有最高許可權!
一些居心不良的人發現,就可以把我們的數據拷走,刪除我們的資料庫,從而勒索贖金!
再次提醒各位同學,別學會所有的技能,大門還一直開著,還抱怨我方防禦塔怎麼一直被摧毀!
以上文CentOS7
安裝為例,修改/etc/mongod.conf
,在security
部分添加如下配置,開啟授權訪問!
security:
authorization: enabled
修改完成之後,重啟 mongodb 服務
#重啟服務
systemctl restart mongod
六、小結
本文主要圍繞 MongoDB 的使用,從環境配置、資料庫使用,再到客戶端工具選用,做了簡單的介紹,可能有的地方總結的不到位,歡迎各位網友批評指出!
在下篇文章中,我們會詳細的介紹SpringBoot
和MongoDB
的整合實踐!
七、參考
作者:程式員志哥
出處:www.pzblog.cn
資源:微信搜【Java極客技術】關註我,回覆 【cccc】有我準備的一線程式必備電腦書籍、大廠面試資料和免費電子書。 希望可以幫助大家提升技術和能力。