1. MongoDB

MongoDB它支持的数据结构非常松散,是一种类JSON的格式 BSON 它即可以存储比较复杂的数据类型 又相当的灵活

MongoDB中的记录是一个文档 它是一个键值对数据结构 MongoDB文档类似于JSON对象 即一个文档认为就是一个对象

2. 体系结构

04. MongoDB - 图1

3. 数据模型

MongoDB的最小存储单位就是文档(document)对象。文档(document)对象对应于关系型数据库的行。数据在MongoDB中以BSON(Binary-JSON)文档的格式存储在磁盘上。

04. MongoDB - 图2

4. 单机部署

https://www.mongodb.com/try/download/community

MongoDB的版本命名规范如:x.y.z;
y为奇数时表示当前版本为开发版,如:1.5.2、4.1.13;
y为偶数时表示当前版本为稳定版,如:1.6.3、4.0.10;
z是修正版本号,数字越大越好。

4.1. windows启动

  1. 解压到本地

  2. 在MongoDB目录下创建 data

  3. 在data文件夹下 分别创建 db 和 logs 文件夹

  4. 进入bin目录下命令行启动

    1. mongod --dbpath=D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\db --logpath=D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\logs\mongolog.log --logappend

MongoDB默认端口为27017 如果要指定端口可以通过—port来设置

  1. mongod --dbpath=D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\db --logpath=D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\logs\mongolog.log --logappend --port 27018

4.1.1. 使用配置文件启动

  1. 在MongoDB目录下conf目录

  2. 进入conf目录创建mongod.conf

    1. storage:
    2. dbPath: D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\db
    3. systemLog:
    4. destination: file
    5. path: D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\logs\mongolog.log
    6. logAppend: true
  1. 在bin目录下命令行启动
    1. mongod -f ../config/mongod.conf
    2. #或者
    3. mongod --config ../config/mongod.conf

4.1.2. 连接数据库

  1. 在bin目录下命令行启动
    1. mongo
    2. #或者
    3. mongo --host=127.0.0.1 --port=27017
  1. show dbs; #查询数据库
  2. exit; #退出

4.1.3. 安装为服务项

在bin目录下执行

  1. mongod --dbpath "D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\db" --logpath "D:\compile\mongodb-win32-x86_64-2012plus-4.2.16\data\logs\mongolog.log" --serviceName "mongodb" --serviceDisplayName "mongodb" --install
  2. net start mongodb

4.2. Linux启动

解压安装

  1. wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.15.tgz
  2. tar -zxvf mongodb-linux-x86_64-rhel70-4.2.15.tgz
  3. mv mongodb-linux-x86_64-rhel70-4.2.15 /usr/local/mongodb
  4. mkdir -p /mongodb/single/data/db #数据目录
  5. mkdir -p /mongodb/single/log #日志文件
  6. vim /mongodb/single/mongod.conf
  1. # 配置内容
  2. systemLog:
  3. # MongoDB发送所有日志输出的目标指定为文件
  4. # The path of the log file to which mongod or mongos should send all diagnostic logging information
  5. destination: file
  6. # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  7. path: "/mongodb/single/log/mongod.log"
  8. # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  9. logAppend: true
  10. storage:
  11. # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  12. # The directory where the mongod instance stores its data.Default Value is "/data/db".
  13. dbPath: "/mongodb/single/data/db"
  14. journal:
  15. # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  16. enabled: true
  17. processManagement:
  18. # 启用在后台运行mongos或mongod进程的守护进程模式。
  19. fork: true
  20. net:
  21. # 服务实例绑定的IP,默认是localhost
  22. bindIp: localhost,192.168.130.212 #ip为当前服务器局域网ip地址 不设置外部无法通过ip访问
  23. # bindIp
  24. # 绑定的端口,默认是27017
  25. port: 27017

启动

  1. /usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf
  2. #/usr/local/mongodb/bin/mongod --config /mongodb/single/mongod.conf
  3. #查看防火墙状态
  4. systemctl status firewalld
  5. #临时关闭防火墙
  6. systemctl stop firewalld
  7. #开机禁止启动防火墙
  8. systemctl disable firewalld

如果一旦数据损坏 导致表死锁

  1. rm -f /mongodb/single/data/db/*.lock #删除锁文件
  2. /usr/local/mongdb/bin/mongod --repair

4.2.1. 配置环境变量

  1. vi /etc/profile
  2. #配置内容
  3. export MONGODB_HOME=/usr/local/mongodb
  4. export PATH=$PATH:$MONGODB_HOME/bin

4.2.2. 配置为服务加入启动

  1. cd /lib/systemd/system
  2. vi mongodb.service
  3. #配置内容
  4. [Unit]
  5. Description=mongodb
  6. After=network.target remote-fs.target nss-lookup.target
  7. [Service]
  8. Type=forking
  9. ExecStart=/usr/local/mongodb/bin/mongod --config /mongodb/single/mongodb.conf
  10. ExecReload=/bin/kill -s HUP $MAINPID
  11. ExecStop=/usr/local/mongodb/bin/mongod --shutdown --config /mongodb/single/mongodb.conf
  12. PrivateTmp=true
  13. [Install]
  14. WantedBy=multi-user.target
  1. #echo "/usr/local/mongodb/bin/mongod --dbpath=/data/db --fork --bind_ip=0.0.0.0 --port 27017 --logpath=/data/db/log --logappend --auth" >> /etc/rc.local
  2. chmod 754 mongodb.service
  1. #启动服务
  2. systemctl start mongodb.service
  3. #关闭服务
  4. systemctl stop mongodb.service
  5. #开机启动
  6. systemctl enable mongodb.service
  7. #关闭开启启动
  8. systemctl disable mongodb.service

4.2.3. 标准的关闭方法

  1. mongo
  2. use admin
  3. db.shutdownServer()

进程id关闭法

  1. ps -ef | grep mongo
  2. kill -2 pid

5. 数据库

5.1. 选择和创建数据库

  1. #use 数据库名称
  2. use articledb #如果没有此数据库则自动创建
  3. #如果新的数据库没有插入数据 showdbs是无法查看到新创建的数据库 因为此时数据库存储在内存当中 并未持久化

5.2. 查询当前有权限查看的数据

  1. show dbs
  2. #或者
  3. show databases

5.3. 查看当前正在使用的数据库名称

  1. db

5.4. 数据库命名规范

数据库名可以是满足以下条件的任意UTF-8字符串。

  • 不能是空字符串( “”)。
  • 不得含有 ‘ ‘(空格)、.、$、/、\和\0 (空字符)。
  • 应全部小写
  • 最多 64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

5.5. 默认三个数据库作用

  • admin : 从权限的角度来看,这是”root”数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
  • local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
  • config : 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息

5.6. 数据库删除

  1. db.dropDatabase() #删除当前使用的库

6. 集合

集合,类似于关系型数据中的表

6.1. 显式创建

  1. #db.createCollection(集合名)
  2. db.createCollection("my") #成功返回1

6.2. 隐式创建

当向一个集合中插入文档时 如果集合不存在 则自动创建集合

通常我们使用隐式创建文档即可

6.3. 查询集合

  1. show collections #查询当前库的所有集合

6.4. 集合删除

  1. #db.集合名.drop()
  2. db.my.drop() #成功则返回true

7. 文档CRUD

文档的数据结构和JSON基本一样

索引存储在集合中数据都是 BSON 格式

7.1. 插入

通过insert() 或者 save() 方法向集合中插入文档

7.1.1. 单问插入

  1. #单文档插入
  2. db.collection.insert(
  3. <document or array of documents>,
  4. {
  5. writeConcern: <document>,
  6. ordered: <boolean>
  7. }
  8. )

04. MongoDB - 图3

  1. #db.集合名.inset({""})
  2. #单文档插入
  3. db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null}) #返回1则插入成功

7.1.2. 批量插入

  1. #批量插入
  2. db.collection.insertMany(
  3. [ <document 1> , <document 2>, ... ],
  4. {
  5. writeConcern: <document>,
  6. ordered: <boolean>
  7. }
  8. )
  9. #db.集合名.insertMany([{""},{""}])
  10. db.comment.insertMany([{"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},{"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},{"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},{"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},{"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}]);

7.1.3. try catch

我们通过批量插入时由于数据较多可能会出现失败 我们可以通过try catch进行异常处理

  1. try {
  2. db.comment.insertMany([
  3. {
  4. _id: '1',
  5. articleid: '100001',
  6. content: '我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。',
  7. userid: '1002',
  8. nickname: '相忘于江湖',
  9. createdatetime: new Date('2019-08-05T22:08:15.522Z'),
  10. likenum: NumberInt(1000),
  11. state: '1',
  12. },
  13. {
  14. _id: '2',
  15. articleid: '100001',
  16. content: '我夏天空腹喝凉开水,冬天喝温开水',
  17. userid: '1005',
  18. nickname: '伊人憔悴',
  19. createdatetime: new Date('2019-08-05T23:58:51.485Z'),
  20. likenum: NumberInt(888),
  21. state: '1',
  22. },
  23. {
  24. _id: '3',
  25. articleid: '100001',
  26. content: '我一直喝凉开水,冬天夏天都喝。',
  27. userid: '1004',
  28. nickname: '杰克船长',
  29. createdatetime: new Date('2019-08-06T01:05:06.321Z'),
  30. likenum: NumberInt(666),
  31. state: '1',
  32. },
  33. {
  34. _id: '4',
  35. articleid: '100001',
  36. content: '专家说不能空腹吃饭,影响健康。',
  37. userid: '1003',
  38. nickname: '凯撒',
  39. createdatetime: new Date('2019-08-06T08:18:35.288Z'),
  40. likenum: NumberInt(2000),
  41. state: '1',
  42. },
  43. {
  44. _id: '5',
  45. articleid: '100001',
  46. content: '研究表明,刚烧开的水千万不能喝,因为烫嘴。',
  47. userid: '1003',
  48. nickname: '凯撒',
  49. createdatetime: new Date('2019-08-06T11:01:02.521Z'),
  50. likenum: NumberInt(3000),
  51. state: '1',
  52. },
  53. ])
  54. } catch (e) {
  55. print(e)
  56. }

7.2. 查询

查询当前数据库中的文档

7.2.1. 查询所有文档

  1. #db.collection.find(<query>, [projection])
  2. db.comment.find()

04. MongoDB - 图4

7.2.2. 条件查询

查询文档中包含此文档内容的所有文档

  1. #db.collection.find({键:"内容"})
  2. db.comment.find({articleid:"100001"})

7.2.3. 只返回第一个结果

  1. #db.collection.findOne({键:"内容"})
  2. db.comment.findOne({articleid:"100001"})

7.2.4. 投影查询

查询出来的文档 只显示需要的键值对 相对应sql中的查询结果只显示指定列

find传参时给出指定的键字段 1为查询此键 0为过滤此键 默认自动包含查询_id键

  1. #db.collection.find({键:"内容"},{键:1,键:0})
  2. db.comment.find({articleid:"100001"},{content:1}) #查询包含100001文档中的 content键内容
  3. db.comment.find({articleid:"100001"},{content:1,_id:0}) #默认查询包含_id 可以通过0过滤

7.3. 更新

  1. //语法
  2. db.collection.update(query, update, options)
  3. //或
  4. db.collection.update(
  5. <query>,
  6. <update>,
  7. {
  8. upsert: <boolean>,
  9. multi: <boolean>,
  10. writeConcern: <document>,
  11. collation: <document>,
  12. arrayFilters: [ <filterdocument1>, ... ],
  13. hint: <document|string> // Available starting in MongoDB 4.2
  14. }
  15. )

04. MongoDB - 图5

7.3.1. 覆盖修改

修改指定文档 并覆盖更新整个文档 即修改为当前语句中的字段 原先字段不保留

  1. db.comment.update({_id:"1"},{likenum:NumberInt(1001)}) #可以理解为删除原文档并插入此文档

7.3.2. 局部修改

我们可以通过修改器$set来修改指定键的内容 并保留原文档其他内容

  1. #默认只修改符合条件的第一条数据
  2. db.comment.update({_id:"2"},{$set:{likenum:NumberInt(778)}})
  3. #修改所有符合条件的数据需要加上参数{multi:true}
  4. db.comment.update({userid:"1003"},{$set:{nickname:"张三"}},{multi:true})

7.3.3. 列值增长修改

通过$inc运算符实现 可以对该键的值进行递增 递减

  1. db.comment.update({_id:"2"},{$inc:{likenum:NumberInt(1)}})

7.4. 删除

7.4.1. 条件删除

删除符合条件的文档

  1. #db.集合.remove({条件})
  2. db.comment.remove({_id:"1"}) #返回值为删除多少条数据

7.4.2. 删除全部

  1. db.comment.remove({})

8. 文档的分页查询

8.1. 统计查询

使用count()方法

  1. db.collection.count(query, options)

04. MongoDB - 图6

8.1.1. 统计当前集合所有文档数

  1. db.comment.count() #返回值是文档数

8.1.2. 按条件查询

  1. db.comment.count({userid:"1003"})

8.2. 分页列表查询

通过limit()方法 读取指定数量的数据 使用skip()方法跳过指定数量的数据

  1. #db.collection.find().limit(number).skip(number)
  2. db.comment.find().limit(3) #查询前3条的数据
  3. db.comment.find().skip(3) #跳过前3条的数据
  4. db.comment.find().skip(0).limit(2) #第一页
  5. db.comment.find().skip(2).limit(2) #第二页

8.3. 排序查询

sort()方法对数据进行排序 使用1和-1来指定升序和降序 sort({键:1}) 默认以id进行升序

  1. db.comment.find().sort({userid:-1,likenum:1}) #对userid的内容进行降序 再对likenum的内容进行升序

8.4. 分页和排序查询的顺序

skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit(),和命令编写顺序无关。

9. 高级查询

9.1. 正则条件查询

  1. #db.集合.find({键:/正则表达式/})
  2. db.comment.find({content:/^专家/})

9.2. 比较查询

  1. db.集合名称.find({ "field" : { $gt: value }}) # 大于: field > value
  2. db.集合名称.find({ "field" : { $lt: value }}) # 小于: field < value
  3. db.集合名称.find({ "field" : { $gte: value }}) # 大于等于: field >= value
  4. db.集合名称.find({ "field" : { $lte: value }}) # 小于等于: field <= value
  5. db.集合名称.find({ "field" : { $ne: value }}) # 不等于: field != value
  6. #例子
  7. db.comment.find({likenum:{$gt:NumberInt(700)}})

9.3. 包含查询

使用$in 查询包含指定内容的文档

  1. db.comment.find({userid:{$in:["1003","1004"]})

9.4. 不包含查询

使用$nin 查询不包含指定内容的文档

  1. db.comment.find({userid:{$nin:["1003","1004"]})

9.5. 条件连接查询

前面我们通过$set查询单条件的文档 如果为多条件则需要使用 $and进行查询

  1. db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]}) # 查询likenum 大于等于700 并且小于2000的文档

9.5.1. 或者连接

使用$or进行查询

  1. db.comment.find({$or:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]}) # 查询likenum 大于等于700 并且小于2000的文档

10. 索引

MongoDB没有下索引下 是进行全集合扫描 如果数据量较大时查询效率非常低

MongoDB索引使用B树数据结构(B-Tree,MySQL是B+Tree)

10.1. 单字段索引

MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引 称为单字段索引

对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。

04. MongoDB - 图7

10.2. 复合索引

复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后
在每个userid的值内,再在按score倒序排序。

04. MongoDB - 图8

10.3. 其他索引

  • 地理空间索引(Geospatial Index)
    为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面
    几何的二维球面索引。

  • 文本索引(Text Indexes)
    MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),
    而将集合中的词作为词干,只存储根词。

  • 哈希索引(Hashed Indexes)
    为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支
    持相等匹配,不支持基于范围的查询。

10.4. 索引管理

10.4.1. 查看索引

返回一个集合中的所有索引的数组 _id主键自带索引为升序

  1. db.comment.getIndexes()

10.4.2. 创建索引

04. MongoDB - 图9

  1. #db.collection.createIndex(keys, options)
  2. db.comment.createIndex({userid:1}) # 给userid创建索引 为升序 索引名默认为键名后加上_(1或者-1)
  3. db.comment.createIndex({userid:1,nickname:-1}) #复合索引

10.4.3. 删除索引

如果要删除文本索引只能通过索引名删除

_id索引无法删除

  1. #db.collection.dropIndex(索引名)
  2. db.comment.dropIndex() #删除所有索引
  3. db.comment.dropIndex("userid_1_nickname_-1") #删除指定索引
  4. db.comment.dropIndex({userid:1}) #根据创建索引条件删除索引

10.5. 索引的使用

分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。
那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看。

  1. #db.collection.find(query,options).explain(options)
  2. db.comment.find({uderid:"1003"}).explain()

关键点看: "stage" : "COLLSCAN", 表示全集合扫描

  1. `"stage"` : `"IXSCAN"` ,基于索引的扫描

10.6. 涵盖查询

Covered Queries
查询条件查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以非常有效。 其实就是查询符合查询条件 索引字段的值

04. MongoDB - 图10

11. Java连接MongoDB

  1. mongodb-driver 是mongo官方推出的java连接mongoDB的驱动包,相当于JDBC驱动。我们通过一个入门的案例来了解mongodb-driver
    的基本使用。
    官方驱动说明和下载: http://mongodb.github.io/mongo-java-driver/
    官方驱动示例文档:http://mongodb.github.io/mongo-java-driver/3.8/driver/getting-started/quick-start/
  2. SpringDataMongoDB SpringData家族成员之一,用于操作MongoDB的持久层框架,封装了底层的mongodb-driver。
    官网主页: https://projects.spring.io/spring-data-mongodb/

12. 评论案例

12.1. 模块搭建

  1. 继承spring-boot项目 导入springdataMongoDB坐标
  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.1.6.RELEASE</version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-test</artifactId>
  11. <scope>test</scope>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-data-mongodb</artifactId>
  16. </dependency>
  17. </dependencies>
  1. 创建application.yml
    1. spring:
    2. data:
    3. mongodb:
    4. host: 192.168.130.212 # 主机地址
    5. database: articledb # 数据库
    6. port: 27017 # 默认端口是27017
    7. #也可以使用uri连接
    8. #uri: mongodb://192.168.40.134:27017/articledb


04. MongoDB - 图11

12.2. 实体类

  1. package com.itcatst.article.po;
  2. import org.springframework.data.annotation.Id;
  3. import org.springframework.data.mongodb.core.index.CompoundIndex;
  4. import org.springframework.data.mongodb.core.index.Indexed;
  5. import org.springframework.data.mongodb.core.mapping.Document;
  6. import org.springframework.data.mongodb.core.mapping.Field;
  7. import java.io.Serializable;
  8. import java.time.LocalDateTime;
  9. import java.util.Date;
  10. /**
  11. * 文章评论实体类
  12. */
  13. //把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。
  14. //@Document(collection="mongodb 对应 collection 名")
  15. // 若未加 @Document ,该 bean save 到 mongo 的 comment collection
  16. // 若添加 @Document ,则 save 到 comment collection
  17. @Document(collection = "comment")//可以省略,如果省略,则默认使用类名小写映射集合 会映射到与类名一致的集合当中
  18. //复合索引
  19. // @CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
  20. public class Comment implements Serializable {
  21. //主键标识,该属性的值会自动对应mongodb的主键字段"_id",如果该属性名就叫“id”,则该注解可以省略,否则必须写
  22. @Id
  23. private String id;//主键
  24. //该属性对应mongodb的字段的名字,如果一致,则无需该注解
  25. @Field("content")
  26. private String content;//吐槽内容
  27. private Date publishtime;//发布日期
  28. //添加了一个单字段的索引
  29. @Indexed
  30. private String userid;//发布人ID
  31. private String nickname;//昵称
  32. private LocalDateTime createdatetime;//评论的日期时间
  33. private Integer likenum;//点赞数
  34. private Integer replynum;//回复数
  35. private String state;//状态
  36. private String parentid;//上级ID
  37. private String articleid;
  38. //getter and setter.....
  39. public String getId() {
  40. return id;
  41. }
  42. public void setId(String id) {
  43. this.id = id;
  44. }
  45. public String getContent() {
  46. return content;
  47. }
  48. public void setContent(String content) {
  49. this.content = content;
  50. }
  51. public Date getPublishtime() {
  52. return publishtime;
  53. }
  54. public void setPublishtime(Date publishtime) {
  55. this.publishtime = publishtime;
  56. }
  57. public String getUserid() {
  58. return userid;
  59. }
  60. public void setUserid(String userid) {
  61. this.userid = userid;
  62. }
  63. public String getNickname() {
  64. return nickname;
  65. }
  66. public void setNickname(String nickname) {
  67. this.nickname = nickname;
  68. }
  69. public LocalDateTime getCreatedatetime() {
  70. return createdatetime;
  71. }
  72. public void setCreatedatetime(LocalDateTime createdatetime) {
  73. this.createdatetime = createdatetime;
  74. }
  75. public Integer getLikenum() {
  76. return likenum;
  77. }
  78. public void setLikenum(Integer likenum) {
  79. this.likenum = likenum;
  80. }
  81. public Integer getReplynum() {
  82. return replynum;
  83. }
  84. public void setReplynum(Integer replynum) {
  85. this.replynum = replynum;
  86. }
  87. public String getState() {
  88. return state;
  89. }
  90. public void setState(String state) {
  91. this.state = state;
  92. }
  93. public String getParentid() {
  94. return parentid;
  95. }
  96. public void setParentid(String parentid) {
  97. this.parentid = parentid;
  98. }
  99. public String getArticleid() {
  100. return articleid;
  101. }
  102. public void setArticleid(String articleid) {
  103. this.articleid = articleid;
  104. }
  105. @Override
  106. public String toString() {
  107. return "Comment{" +
  108. "id='" + id + '\'' +
  109. ", content='" + content + '\'' +
  110. ", publishtime=" + publishtime +
  111. ", userid='" + userid + '\'' +
  112. ", nickname='" + nickname + '\'' +
  113. ", createdatetime=" + createdatetime +
  114. ", likenum=" + likenum +
  115. ", replynum=" + replynum +
  116. ", state='" + state + '\'' +
  117. ", parentid='" + parentid + '\'' +
  118. ", articleid='" + articleid + '\'' +
  119. '}';
  120. }
  121. }
  • @Document(collection = “comment”) 声明为mongodb文档 并且映射到comment集合中 如果当前实体类名与集合一致则collection可以忽略(并且只能是小写名称的实体类)
  • @CompoundIndex( def = “{‘userid’: 1, ‘nickname’: -1}”) 复合索引 def属性与设置复活索引条件一致 为键和排序方式
  • @Id 声明此属性为主键 如果属性名为id则该注解可以省略不加
  • @Field(“content”) 当成员属性名称与集合中的键字段不一致时 可以使用该注解映射为集合中指定的键字段 此时映射为content键字段
  • @Indexed 添加为单字段索引

12.3. 增删改查方法

  1. 创建dao层接口 并继承MongoRepository 泛型为 实体类 和 id的类型 ```java package com.itcatst.article.dao;

import com.itcatst.article.po.Comment; import org.springframework.data.mongodb.repository.MongoRepository;

public interface CommentRepository extends MongoRepository { }

  1. 2.
  2. 创建Service 注入dao 并调用动态代理里的方法
  3. ```java
  4. package com.itcatst.article.service;
  5. import com.itcatst.article.dao.CommentRepository;
  6. import com.itcatst.article.po.Comment;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Service;
  9. import java.util.List;
  10. @Service
  11. public class CommentService {
  12. @Autowired
  13. private CommentRepository commentRepository;
  14. /**
  15. * 保存一个评论
  16. *
  17. * @param comment
  18. */
  19. public void saveComment(Comment comment) {
  20. //如果需要自定义主键,可以在这里指定主键;如果不指定主键,MongoDB会自动生成主键
  21. //设置一些默认初始值。。。
  22. //调用dao
  23. commentRepository.save(comment);
  24. }
  25. /**
  26. * 更新评论
  27. *
  28. * @param comment
  29. */
  30. public void updateComment(Comment comment) {
  31. //调用dao
  32. commentRepository.save(comment);
  33. }
  34. /**
  35. * 根据id删除评论
  36. *
  37. * @param id
  38. */
  39. public void deleteCommentById(String id) {
  40. //调用dao
  41. commentRepository.deleteById(id);
  42. }
  43. /**
  44. * 查询所有评论
  45. *
  46. * @return
  47. */
  48. public List<Comment> findCommentList() {
  49. //调用dao
  50. return commentRepository.findAll();
  51. }
  52. /**
  53. * 根据id查询评论
  54. *
  55. * @param id
  56. * @return
  57. */
  58. public Comment findCommentById(String id) {
  59. //调用dao
  60. return commentRepository.findById(id).get();
  61. }
  62. }

12.4. 创建测试方法

  1. 新建junit测试方法 类路径要与主程序一致 ```java package com.itcatst.article.service;

import com.itcatst.article.po.Comment; import com.itcatst.article.service.CommentService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;

import java.time.LocalDateTime; import java.util.List;

@RunWith(SpringRunner.class) @SpringBootTest public class CommentServiceTest {

  1. @Autowired
  2. private CommentService commentService;
  3. @Test
  4. public void testFindCommentList() {
  5. List<Comment> commentList = commentService.findCommentList();
  6. System.out.println(commentList);
  7. }
  8. @Test
  9. public void testFndCommentById() {
  10. Comment commentById = commentService.findCommentById("1");
  11. System.out.println(commentById);
  12. }
  13. /**
  14. * 保存一个评论
  15. */
  16. @Test
  17. public void testSaveComment() {
  18. Comment comment = new Comment();
  19. //此处没有指定id 但MongoDB默认自动生成 我们推荐自动生成 不推荐自己书写id
  20. comment.setArticleid("100000");
  21. comment.setContent("测试添加的数据");
  22. comment.setCreatedatetime(LocalDateTime.now());
  23. comment.setUserid("1003");
  24. comment.setNickname("凯撒大帝");
  25. comment.setState("1");
  26. comment.setLikenum(0);
  27. comment.setReplynum(0);
  28. commentService.saveComment(comment);
  29. }

}

  1. <a name="14ae450a"></a>
  2. ## 12.5. 分页查询测试
  3. 1.
  4. 在dao层接口创建新的方法 必须要指定**对应的属性名为方法名**否则会报错
  5. <br />格式: Page<实体类> findBy根据哪个属性来查询(传递属性类型 属性名,Pageable pageable);
  6. ```java
  7. ////根据父id,查询子评论的分页列表
  8. Page<Comment> findByParentid(String parentid, Pageable pageable);
  1. 在service层调用dao层的方法
    1. /**
    2. * 分页查询
    3. *
    4. * @param parentid 根据哪个属性来查询
    5. * @param page 页码
    6. * @param size 每页个数
    7. * @return
    8. */
    9. public Page<Comment> findCommentListByParentid(String parentid, int page, int size) {
    10. return commentRepository.findByParentid(parentid, PageRequest.of(page-1, size));
    11. }
  1. 测试用例 ```java @Test public void testFindCommentListByParentid(){ Page page = commentService.findCommentListByParentid(“3”, 1, 2); System.out.println(page.getTotalElements());//返回总条数 List content = page.getContent(); //返回结果的集合 System.out.println(content);

}

  1. <a name="4bf73c0d"></a>
  2. ## 12.6. 评论点赞
  3. 最简单的方法就是根据id查询当前对应的文档 并将点赞数+1 但执行效率不高 因为只需要修改点赞数 没有必要把所有的字段都查询出来
  4. 我们可以使用 MongoTemplate 类实现对某列进行操作
  5. 1.
  6. 在service层注入 MongoTemplate 并编修改方法
  7. ```java
  8. @Autowired
  9. private MongoTemplate mongoTemplate;
  10. /**
  11. * 点赞数+1
  12. *
  13. * @param id
  14. */
  15. public void updateCommentLikenum(String id) {
  16. //查询条件
  17. //Query query = Query.query(Criteria.where("_id").is(id)).addCriteria(Criteria.where("nickname").is("凯撒大帝")); //使用Criteria.when(键字段).is(条件) 判断条件 addCriteria可以无限扩展条件
  18. Query query = Query.query(Criteria.where("_id").is(id));
  19. //更新条件
  20. Update update = new Update();
  21. update.inc("likenum",1); //将likenum数+1 如单传键字段则自动加1
  22. // update.set()
  23. mongoTemplate.updateFirst(query, update, Comment.class);
  24. }

13. 副本集

MongoDB中的副本集(Replica Set)是一组维护相同数据集的mongod服务。 副本集可提供冗余和高
可用性,是所有生产部署的基础。

主从复制和副本集区别
主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂
掉后,又在剩下的从节点中选中其他节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多
个备份节点(从、secondary)。

副本集有两种类型三种角色:

两种类型:

  • 主节点( Primary)类型:数据操作的主要连接点,可读写。
  • 次要(辅助、从)节点( Secondaries)类型:数据冗余备份节点,可以读或选举。

三种角色:

  • 主要成员(Primary):主要接收所有写操作。就是主节点。
  • 副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可
    以读操作(但需要配置)。是默认的一种从节点类型。
  • 仲裁者( Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副
    本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

13.1. 副本集创建

13.1.1. 主节点

  1. #主节点
  2. mkdir -p /mongodb/replica_sets/myrs_27017/log \ & #日志文件
  3. mkdir -p /mongodb/replica_sets/myrs_27017/data/db #数据文件
  4. vim /mongodb/replica_sets/myrs_27017/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/replica_sets/myrs_27017/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/replica_sets/myrs_27017/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #bindIp
  25. #绑定的端口
  26. port: 27017
  27. replication:
  28. #副本集的名称 同一个副本集中集群必须一致
  29. replSetName: myrs

启动主节点

  1. /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf

13.1.2. 从节点

  1. #副本节点
  2. mkdir -p /mongodb/replica_sets/myrs_27018/log \ &
  3. mkdir -p /mongodb/replica_sets/myrs_27018/data/db
  4. vim /mongodb/replica_sets/myrs_27018/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/replica_sets/myrs_27018/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/replica_sets/myrs_27018/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/replica_sets/myrs_27018/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #bindIp
  25. #绑定的端口
  26. port: 27018
  27. replication:
  28. #副本集的名称
  29. replSetName: myrs

启动节点

  1. /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf

13.1.3. 仲裁节点

  1. #仲裁节点
  2. mkdir -p /mongodb/replica_sets/myrs_27019/log \ &
  3. mkdir -p /mongodb/replica_sets/myrs_27019/data/db
  4. vim /mongodb/replica_sets/myrs_27019/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/replica_sets/myrs_27019/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/replica_sets/myrs_27019/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/replica_sets/myrs_27019/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #bindIp
  25. #绑定的端口
  26. port: 27019
  27. replication:
  28. #副本集的名称
  29. replSetName: myrs

启动节点

  1. /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf

13.2. 初始化配置副本集和主节点

  1. #使用mongo客户端任意节点都可以 但尽量连上主节点
  2. /usr/local/mongodb/bin/mongo --host=192.168.130.212 --port=27017
  3. #初始化命令
  4. rs.initiate() #使用默认的配置来初始化副本集 “ok”的值为1,说明创建成功 并且此节点变为主节点
  5. rs.conf() #查看默认节点配置
  6. rs.status() # 查询副本集状态

13.3. 添加副本从节点

  1. #rs.add(host:post)
  2. rs.add(192.168.130.212:27018)
  3. rs.status() #查看副本集状态

13.4. 添加仲裁节点

  1. #rs.addArb(host:post)
  2. rs.addarB(192.168.130.212:27019)
  3. rs.status() #查看副本集状态

13.5. 副本集的数据读写操作

  1. 只有主节点写入数据和读取数据

  2. 默认情况从节点无法读取数据 也无法写入数据 可以进行设置增加读的权限

    1. #连接从节点的客户端
    2. rs.slaveOk() #该命令是 db.getMongo().setSlaveOk() 的简化命令
    3. #或者
    4. rs.slaveOk(true)
    5. #此时实现了读写分离 让主插入数据 让从来读取数据
  1. 仲裁者节点,不存放任何业务数据的,可以登录查看 只存放副本集配置等数据。

13.6. 主节点的选举原则

MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:

  1. 主节点故障
  2. 主节点网络不可达(默认心跳信息为10秒)
  3. 人工干预(rs.stepDown(600))

选举规则是根据票数来决定谁获胜:

  • 票数最高,且获得了 “大多数”成员的投票支持的节点获胜。
    “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,
    则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,
    复制集将无法提供写服务,处于只读状态。
  • 若票数相同,且都获得了 “大多数”成员的投票支持的,数据新的节点获胜。
    数据的新旧是通过操作日志oplog来对比的。

在获得票数的时候,优先级(priority)参数影响重大。
可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加
0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员
更有资格成为主要成员,更低的值可使成员更不符合条件。
默认情况下,优先级的值是1

13.7. 提升优先级

  1. #先导出配置到变量中
  2. cfg=rs.conf()
  3. #修改指定优先级 ID号默认从0开始
  4. cfg.members[1].priority=2
  5. #重新加载配置
  6. rs.reconfig(cfg)

13.8. Compass连接副本集

  1. #将host修改为当前主节点的ip
  2. var config = rs.config();
  3. config.members[0].host="192.168.130.212:27017";rs.reconfig(config)

04. MongoDB - 图12

选择Primary 为主节点 Secondary为副本集

13.9. SpringDataMongoDB连接副本集

mongodb://host1,host2,host3/articledb?connect=replicaSet&slaveOk=true&replicaSet=副本集名字

  • slaveOk=true :开启副本节点读的功能,可实现读写分离。
  • connect=replicaSet :自动到副本集中选择读写的主机。如果slaveOK是打开的,则实现了读写分

主机必须是副本集中所有的主机,包括主节点、副本节点、仲裁节点。

  1. spring:
  2. data:
  3. mongodb:
  4. # host: 192.168.130.212 # 主机地址
  5. # database: articledb # 数据库
  6. # port: 27017 # 默认端口是27017
  7. #也可以使用uri连接
  8. #uri: mongodb://192.168.40.134:27017/articledb
  9. # 副本集的连接字符串
  10. uri: mongodb://192.168.42.212:27017,192.168.42.212:27018,192.168.42.212:27019/article
  11. db?connect=replicaSet&slaveOk=true&replicaSet=myrs

14. 分片集群

分片(sharding)是一种跨多台机器分布数据的方法, MongoDB使用分片来支持具有非常大的数据集
和高吞吐量操作的部署。

MongoDB分片群集包含以下组件:

  • 分片(存储):每个分片包含分片数据的子集。 每个分片都可以部署为副本集。
  • mongos (路由):mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口。
  • config servers (“调度”的配置):配置服务器存储群集的元数据和配置设置。 从MongoDB 3.4开
    始,必须将配置服务器部署为副本集(CSRS)。

04. MongoDB - 图13

14.1. 搭建分片集群架构

04. MongoDB - 图14

14.1.1. 第一个副本集

  1. #-----------myshardrs01
  2. mkdir -p /mongodb/sharded_cluster/myshardrs01_27018/log \ &
  3. mkdir -p /mongodb/sharded_cluster/myshardrs01_27018/data/db \ &
  4. mkdir -p /mongodb/sharded_cluster/myshardrs01_27118/log \ &
  5. mkdir -p /mongodb/sharded_cluster/myshardrs01_27118/data/db \ &
  6. mkdir -p /mongodb/sharded_cluster/myshardrs01_27218/log \ &
  7. mkdir -p /mongodb/sharded_cluster/myshardrs01_27218/data/db
  8. #myshardrs01_27018
  9. vim /mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myshardrs01_27018/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #bindIp
  25. #绑定的端口
  26. port: 27018
  27. replication:
  28. #副本集的名称
  29. replSetName: myshardrs01
  30. sharding:
  31. #分片角色
  32. clusterRole: shardsvr

clusterRole 设置分片角色:

  • shardsvr 分片角色
  • configsvr 配置角色
  1. #myshardrs01_27118
  2. vim /mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myshardrs01_27118/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #绑定的端口
  25. port: 27118
  26. replication:
  27. replSetName: myshardrs01
  28. sharding:
  29. clusterRole: shardsvr
  1. #myshardrs01_27218
  2. vim /mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myshardrs01_27218/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.pid"
  19. net:
  20. #服务实例绑定的IP
  21. bindIp: localhost,192.168.42.130.212
  22. #绑定的端口
  23. port: 27218
  24. replication:
  25. replSetName: myshardrs01
  26. sharding:
  27. clusterRole: shardsvr

启动第一套副本集:一主一副本一仲裁

  1. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
  2. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
  3. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
  • 初始化副本集和创建主节点
  1. /usr/local/mongodb/bin/mongo --host 192.168.130.212 --port 27018 #尽量连接主节点
  1. rs.initiate() #初始化主节点
  2. rs.status() #状态查看
  3. rs.add("192.168.130.212:27118") #添加副节点
  4. rs.addArb("192.168.130.212:27218") #添加仲裁节点
  5. rs.conf()

14.1.2. 第二套副本集

  1. #-----------myshardrs02
  2. mkdir -p /mongodb/sharded_cluster/myshardrs02_27318/log \ &
  3. mkdir -p /mongodb/sharded_cluster/myshardrs02_27318/data/db \ &
  4. mkdir -p /mongodb/sharded_cluster/myshardrs02_27418/log \ &
  5. mkdir -p /mongodb/sharded_cluster/myshardrs02_27418/data/db \ &
  6. mkdir -p /mongodb/sharded_cluster/myshardrs02_27518/log \ &
  7. mkdir -p /mongodb/sharded_cluster/myshardrs02_27518/data/db
  1. #myshardrs02_27318
  2. vim /mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myshardrs02_27318/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.pid"
  19. net:
  20. #服务实例绑定的IP
  21. bindIp: localhost,192.168.130.212
  22. #绑定的端口
  23. port: 27318
  24. replication:
  25. replSetName: myshardrs02
  26. sharding:
  27. clusterRole: shardsvr
  1. #myshardrs02_27418
  2. vim /mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myshardrs02_27418/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #绑定的端口
  25. port: 27418
  26. replication:
  27. replSetName: myshardrs02
  28. sharding:
  29. clusterRole: shardsvr
  1. #myshardrs02_27518
  2. vim /mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myshardrs02_27518/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #绑定的端口
  25. port: 27518
  26. replication:
  27. replSetName: myshardrs02
  28. sharding:
  29. clusterRole: shardsvr

启动第二套副本集:一主一副本一仲裁

  1. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
  2. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
  3. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
  4. ps -ef |grep mongod #一共6个服务
  • 初始化副本集和创建主节点
  1. /usr/local/mongodb/bin/mongo --host 192.168.130.212 --port 27318 #尽量连接主节点
  1. rs.initiate() #初始化主节点
  2. rs.status() #状态查看
  3. rs.add("192.168.130.212:27418") #添加副节点
  4. rs.addArb("192.168.130.212:27518") #添加仲裁节点
  5. rs.conf()

14.1.3. 配置节点副本集

  1. #-----------configrs
  2. #建立数据节点data和日志目录
  3. mkdir -p /mongodb/sharded_cluster/myconfigrs_27019/log \ &
  4. mkdir -p /mongodb/sharded_cluster/myconfigrs_27019/data/db \ &
  5. mkdir -p /mongodb/sharded_cluster/myconfigrs_27119/log \ &
  6. mkdir -p /mongodb/sharded_cluster/myconfigrs_27119/data/db \ &
  7. mkdir -p /mongodb/sharded_cluster/myconfigrs_27219/log \ &
  8. mkdir -p /mongodb/sharded_cluster/myconfigrs_27219/data/db
  1. #myconfigrs_27019
  2. vim /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
  1. #MongoDB发送所有日志输出的目标指定为文件
  2. destination: file
  3. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  4. path: "/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.log"
  5. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  6. logAppend: true
  7. storage:
  8. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  9. dbPath: "/mongodb/sharded_cluster/myconfigrs_27019/data/db"
  10. journal:
  11. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  12. enabled: true
  13. processManagement:
  14. #启用在后台运行mongos或mongod进程的守护进程模式。
  15. fork: true
  16. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  17. pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.pid"
  18. net:
  19. #服务实例绑定所有IP
  20. #bindIpAll: true
  21. #服务实例绑定的IP
  22. bindIp: localhost,192.168.130.212
  23. #绑定的端口
  24. port: 27019
  25. replication:
  26. replSetName: myconfigrs
  27. sharding:
  28. clusterRole: configsvr

此时分片角色为配置角色

  1. #myconfigrs_27119
  2. vim /mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myconfigrs_27119/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.130.212
  24. #绑定的端口
  25. port: 27119
  26. replication:
  27. replSetName: myconfigrs
  28. sharding:
  29. clusterRole: configsvr
  1. #myconfigrs_27219
  2. vim /mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. storage:
  9. #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  10. dbPath: "/mongodb/sharded_cluster/myconfigrs_27219/data/db"
  11. journal:
  12. #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  13. enabled: true
  14. processManagement:
  15. #启用在后台运行mongos或mongod进程的守护进程模式。
  16. fork: true
  17. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  18. pidFilePath: "/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.pid"
  19. net:
  20. #服务实例绑定所有IP
  21. #bindIpAll: true
  22. #服务实例绑定的IP
  23. bindIp: localhost,192.168.42.130.212
  24. #绑定的端口
  25. port: 27219
  26. replication:
  27. replSetName: myconfigrs
  28. sharding:
  29. clusterRole: configsvr

启动配置副本集:一主两副本

  1. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
  2. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
  3. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
  4. ps -ef |grep mongod #一共9个服务
  • 初始化副本集和创建主节点
  1. /usr/local/mongodb/bin/mongo --host 192.168.130.212 --port 27019 #尽量连接主节点
  1. rs.initiate() #初始化主节点
  2. rs.status() #状态查看
  3. rs.add("192.168.130.212:27119") #添加副节点
  4. rs.add("192.168.130.212:27119") #添加副节点
  5. rs.conf()

14.1.4. 路由节点创建和连接

  1. #-----------mongos01
  2. mkdir -p /mongodb/sharded_cluster/mymongos_27017/log
  1. #mymongos_27017节点
  2. vi /mongodb/sharded_cluster/mymongos_27017/mongos.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/mymongos_27017/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. processManagement:
  9. #启用在后台运行mongos或mongod进程的守护进程模式。
  10. fork: true
  11. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  12. pidFilePath: /mongodb/sharded_cluster/mymongos_27017/log/mongod.pid"
  13. net:
  14. #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  15. #bindIpAll: true
  16. #服务实例绑定的IP
  17. bindIp: localhost,192.168.130.212
  18. #bindIp
  19. #绑定的端口
  20. port: 27017
  21. sharding:
  22. #指定配置节点副本集
  23. configDB: myconfigrs/192.168.42.130.212:27019,192.168.42.130.212:27119,192.168.42.130.212:27219

configDB 地址为 配置副本集名称/配置节点1,配置节点2,配置节点3

  1. #启动
  2. /usr/local/mongodb/bin/mongos -f /mongodb/sharded_cluster/mymongos_27017/mongos.conf
  1. #连接 此时为mongos
  2. /usr/local/mongodb/bin/mongo --host 192.168.130.212 --port 27017

通过路由节点操作,现在只是连接了配置节点,还没有连接分片数据节点,因此写不进去数据,如果写数据会报错。

14.1.5. 路由节点添加分片

  1. #sh.addShard(副本集名称/主节点,副本节点,仲裁节点) 三种角色节点必须都添加到路由中
  2. sh.addShard("myshardrs01/192.168.42.130.212:27018,192.168.42.130.212:27118,192.168.42.130.212:27218") #第一套
  3. sh.addShard("myshardrs02/192.168.42.130.212:27318,192.168.42.130.212:27418,192.168.42.130.212:27518") #第二套
  4. sh.status() #查询分片状态
  5. #sh.enableSharding("库名")
  6. sh.enableSharding("articledb") #开启分片功能

14.1.5.1. 集合分片和分片规则

sh.shardCollection(namespace, key, unique)

04. MongoDB - 图15

  1. 分片规则一:哈希策略
    对指定字段的值 进行哈希计算出存放的位置 每个副本集对应则对应的范围 通过哈希计算出存放的副本集中
    1. sh.shardCollection("articledb.comment",{"nickname":"hashed"})
  1. 分片规则二:范围策略
    对于 基于范围的分片 ,MongoDB按键的范围把数据分成不同部分.
    1. sh.shardCollection("articledb.author",{"age":1})

注意事项:

  • 一个集合只能指定一个片键,否则报错。
  • 一旦对一个集合分片,分片键和分片值就不可改变。 如:不能给集合选择不同的分片键、不能更新
    分片键的值。
  • 根据age索引进行分配数据

如果添加分片失败,需要先手动移除分片,检查添加分片的信息的正确性后,再次添加分片。

  1. use admin
  2. db.runCommand( { removeShard: "myshardrs02" } )
  1. db.printShardingStatus() #显示集群的详细信息
  2. sh.isBalancerRunning() #查询交换器是否工作
  3. sh.getBalancerState() #查看Balancer状态

14.1.5.2. 范围规则配置数据块大小

范围规则默认存放在数据块中 如果数据块(chunk)没有填满,默认的数据块尺寸(chunksize)是64M,填满后才会考虑向其他片的数据块填充数据

  1. use config
  2. db.settings.save({_id:"chunksize", value: 64}) #默认为64m

14.1.6. 追加路由节点

  1. #-----------mongos02
  2. mkdir -p /mongodb/sharded_cluster/mymongos_27117/log
  1. vi /mongodb/sharded_cluster/mymongos_27117/mongos.conf
  1. systemLog:
  2. #MongoDB发送所有日志输出的目标指定为文件
  3. destination: file
  4. #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  5. path: "/mongodb/sharded_cluster/mymongos_27117/log/mongod.log"
  6. #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  7. logAppend: true
  8. processManagement:
  9. #启用在后台运行mongos或mongod进程的守护进程模式。
  10. fork: true
  11. #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  12. pidFilePath: /mongodb/sharded_cluster/mymongos_27117/log/mongod.pid"
  13. net:
  14. #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  15. #bindIpAll: true
  16. #服务实例绑定的IP
  17. bindIp: localhost,192.168.0.2
  18. #bindIp
  19. #绑定的端口
  20. port: 27117
  21. sharding:
  22. configDB:
  23. myconfigrs/192.168.42.130.212:27019,192.168.42.130.212:27119,192.168.42.130.212:27219
  1. #启动
  2. /usr/local/mongodb/bin/mongos -f /mongodb/sharded_cluster/mymongos_27117/mongos.conf

第二个路由无需配置,因为分片配置都保存到了配置服务器中了。

14.2. Compass连接分片集群

连接路由节点即可

04. MongoDB - 图16

14.3. SpringDataMongDB 连接分片集群

  1. spring:
  2. data:
  3. mongodb:
  4. # host: 192.168.130.212 # 主机地址
  5. # database: articledb # 数据库
  6. # port: 27017 # 默认端口是27017
  7. #也可以使用uri连接
  8. #uri: mongodb://192.168.40.134:27017/articledb
  9. # 副本集的连接字符串
  10. uri: mongodb://192.168.40.134:27017,192.168.40.134:27117/articledb
  11. # uri: mongodb://192.168.42.212:27017,192.168.42.212:27018,192.168.42.212:27019/article
  12. # db?connect=replicaSet&slaveOk=true&replicaSet=myrs

如果有多个节点可以使用逗号隔开 SpringDataMongDB默认有负载均衡策略

15. 安全认证

默认情况下,MongoDB实例启动运行时是没有启用用户访问权限控制的

15.1. 角色

常用的内置角色:

  • 数据库用户角色: read、readWrite;
  • 所有数据库用户角色: readAnyDatabase、readWriteAnyDatabase、
  • userAdminAnyDatabase、dbAdminAnyDatabase
  • 数据库管理角色: dbAdmin、dbOwner、userAdmin;
  • 集群管理角色: clusterAdmin、clusterManager、clusterMonitor、hostManager;
  • 备份恢复角色: backup、restore;
  • 超级用户角色: root
  • 内部角色: system

04. MongoDB - 图17

  1. db.runCommand({ rolesInfo: 1 }) #查询所有角色权限(仅用户自定义角色)
  2. db.runCommand({ rolesInfo: 1, showBuiltinRoles: true }) #查询所有角色权限(包含内置角色)
  3. db.runCommand({ rolesInfo: "<rolename>" }) #查询当前数据库中的某角色的权限
  4. db.runCommand({ rolesInfo: { role: "<rolename>", db: "<database>" } } #查询其它数据库中指定的角色权限

15.2. 单实例安全认证

  • 添加用户和权限
  1. use admin
  2. db.createUser({user:"myroot",pwd:"123456",roles:["root"]}) #创建myroot用户 密码123456 权限为root 如果不指定db名称则默认为当前所在库
  3. db.createUser({user:"myadmin",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]}) #创建一个在指定库中管理用户的用户
  4. db.system.users.find() #查询已经创建的用户情况
  5. db.dropUser("myadmin") #删除指定用户
  6. db.changeUserPassword("myroot", "123456") #修改指定用户密码
  1. 本案例创建了两个用户,分别对应超管和专门用来管理用户的角色,事实上,你只需要一个用户即
    可。如果你对安全要求很高,防止超管泄漏,则不要创建超管用户。
  2. 和其它数据库(MySQL)一样,权限的管理都差不多一样,也是将用户和权限信息保存到数据库对
    应的表中。Mongodb存储所有的用户信息在admin 数据库的集合system.users中,保存用户名、密码
    和数据库信息。
  3. 如果不指定数据库,则创建的指定的权限的用户在所有的数据库上有效,如 {role:"userAdminAnyDatabase", db:""}
  • 认证测试
  1. use admin
  2. db.auth("myroot","123456")

如果开启了认证后,登录的客户端的用户必须使用admin库的角色,如拥有root角色的myadmin用
户,再通过myadmin用户去创建其他角色的用户

15.2.1. 服务端开启认证和客户端连接登陆

  1. 参数方式 启动服务端时加锁—auth参数
    1. /usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf --auth
  1. 配置方式 ```sh vim /mongodb/single/mongod.conf

配置文件追加

security: authorization: enabled #开启授权认证

  1. ```sh
  2. #此时连接可以进入客户端 但无法执行任何操作 只有认证成功后能使用
  3. use admin #此用户能查看什么库就切换到什么库中再认证 否则报错
  4. db.auth("myroot","123456")

连接客户端时直接认证 同样查看什么库就切换到什么库中再认证 否则报错

  1. mongo --host 192.168.42.130.212 --port 27017 --authenticationDatabase admin -u myroot -p 123456
  • -u :用户名
  • -p :密码
  • — authenticationDatabase :指定连接到哪个库。当登录是指定用户名密码时,必须指定对应的
    数据库!

15.2.2. SpringDataMongoDB连接认证

  1. spring:
  2. #数据源配置
  3. data:
  4. mongodb:
  5. # 主机地址
  6. # host: 192.168.42.130.212
  7. # 数据库
  8. # database: articledb
  9. # 默认端口是27017
  10. # port: 27017
  11. #帐号
  12. # username: bobo
  13. #密码
  14. # password: 123456
  15. #单机有认证的情况下,也使用字符串连接
  16. uri: mongodb://bobo:123456@192.168.130.212/articledb

15.3. 副本集环境

只需要在主节点上添加用户,副本集会自动同步

  1. use admin
  2. db.createUser({user:"myroot",pwd:"123456",roles:["root"]})

生成副本集认证的key文件 在centos中

  1. openssl rand -base64 90 -out ./mongo.keyfile
  2. chmod 400 ./mongo.keyfile
  3. ll mongo.keyfile

所有副本集节点都必须要用同一份keyfile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须
有读的权限,否则将来会报错

  1. #此时应该通过网络传输此key文件给集群机器
  2. cp mongo.keyfile /mongodb/replica_sets/myrs_27017
  3. cp mongo.keyfile /mongodb/replica_sets/myrs_27018
  4. cp mongo.keyfile /mongodb/replica_sets/myrs_27019

修改各个节点的配置文件

  1. vim /mongodb/replica_sets/myrs_27017/mongod.conf
  1. security:
  2. #KeyFile鉴权文件
  3. keyFile: /mongodb/replica_sets/myrs_27017/mongo.keyfile
  4. #开启认证方式运行
  5. authorization: enabled
  1. vim /mongodb/replica_sets/myrs_27018/mongod.conf
  1. security:
  2. #KeyFile鉴权文件
  3. keyFile: /mongodb/replica_sets/myrs_27018/mongo.keyfile
  4. #开启认证方式运行
  5. authorization: enabled
  1. vim /mongodb/replica_sets/myrs_27019/mongod.conf
  1. security:
  2. #KeyFile鉴权文件
  3. keyFile: /mongodb/replica_sets/myrs_27019/mongo.keyfile
  4. #开启认证方式运行
  5. authorization: enabled

重新启动

  1. /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf
  2. /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf
  3. /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf

创建新的用户读和写

  1. mongo
  2. use admin
  3. db.auth("myroot","123456") #先登陆认证管理员账号
  4. use articledb
  5. db.createUser({user: "bobo", pwd: "123456", roles: ["readWrite"]})

13.9. SpringDataMongoDB连接副本集

  1. spring:
  2. #数据源配置
  3. data:
  4. mongodb:
  5. #副本集有认证的情况下,字符串连接
  6. uri:
  7. mongodb://bobo:123456@192.168.42.130.212:27017,192.168.42.130.212:27018,192.168.42.130.212:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs

15.4. 分片集群环境

关闭配置服务器副本集的服务,建议依次关闭副本节点、主节点再关闭路由服务器的服务

  1. rs.stepDown() #告知副本集说本机要下线
  2. use admin
  3. db.shutdownServer()
  1. 生成key文件
  1. openssl rand -base64 90 -out ./mongo.keyfile
  2. chmod 400 ./mongo.keyfile
  1. 拷贝key文件到各个服务上

  2. 修改配置文件

    1. #这里是各个服务上的配置文件
    2. vim /mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
  1. security:
  2. #KeyFile鉴权文件 注意要修改路径
  3. keyFile: /mongodb/replica_sets/myrs_27019/mongo.keyfile
  4. #开启认证方式运行
  5. authorization: enabled
  1. 重新启动各个节点
    先启动配置节点,再启动分片节点,最后启动路由节点。如果先启动分片节点,会卡住
    1. /usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
  1. 客户端mongo,通过localhost登录任意一个mongos路由
    1. /usr/local/mongodb/bin/mongo --port 27017
  1. 创建账号
    1. use admin
    2. db.createUser({user:"myroot",pwd:"123456",roles:["root"]}) #管理员账号
    3. db.createUser({user: "bobo", pwd: "123456", roles: [{ role: "readWrite",db: "articledb" }]}) #指定库读写账号

15.2.2. SpringDataMongoDB连接认证

  1. spring:
  2. #数据源配置
  3. data:
  4. mongodb:
  5. # 分片集群有认证的情况下,字符串连接
  6. uri:
  7. mongodb://bobo:123456@192.168.42.130.212:27017,192.168.42.130.212:27117/articledb

16. 4.0新特性

16.1. 加载外部js文件

加载当前路径下的js文件 启动shell命令时的路径和js所在路径要一致

  1. load("aaa.js") #返回true则成功

16.2. 事务性

  1. package com.itheima.sh.demo_01;
  2. import com.mongodb.MongoClient;
  3. import com.mongodb.ServerAddress;
  4. import com.mongodb.client.*;
  5. import com.mongodb.client.model.Filters;
  6. import org.bson.Document;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. import static com.mongodb.client.model.Filters.eq;
  10. import static com.mongodb.client.model.Updates.inc;
  11. public class Demo02 {
  12. static MongoClient mongoClient;
  13. static MongoDatabase mongoDatabase;
  14. static MongoCollection<Document> collection;
  15. public static void main(String[] args) throws Exception{
  16. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. //副本集
  18. final List<ServerAddress> servers=new ArrayList<ServerAddress>();
  19. servers.add(new ServerAddress("127.0.0.1", 27000));
  20. servers.add(new ServerAddress("127.0.0.1", 27001));
  21. servers.add(new ServerAddress("127.0.0.1", 27002));
  22. mongoClient = new MongoClient(servers);
  23. // 连接到数据库 itcast表示数据库名
  24. mongoDatabase = mongoClient.getDatabase("itcast");
  25. //打印数据库最开始的状态
  26. printDataState();
  27. //转账 带事务的
  28. transerTransacFunds("a", "b", 100);
  29. }
  30. //带事务的转账
  31. private static void transerTransacFunds(String a, String b, int money) {
  32. System.out.println("------------使用事务------------");
  33. System.out.println("a向b转账100元,有可能会发生异常,回到之前的状态。两个人的操作在同一个事务中");
  34. System.out.println("-------------------------------");
  35. //获取session
  36. ClientSession session = mongoClient.startSession();
  37. try {
  38. //开启事务
  39. session.startTransaction();
  40. //a减100
  41. minusTransacFromA(session, a, money);
  42. //模拟异常
  43. int x = 1 / 0;
  44. //b加100
  45. addTransacToB(session, b, money);
  46. //提交事务
  47. session.commitTransaction();
  48. } catch (Exception e) {
  49. System.out.println("带事务,转账失败,回到开启事务之前的状态");
  50. //回滚事务
  51. session.abortTransaction();
  52. } finally {
  53. //关闭session
  54. session.close();
  55. //输出账户状态
  56. printDataState();
  57. }
  58. }
  59. //带事务b加100
  60. private static void addTransacToB(ClientSession session, String b, int money) {
  61. System.out.println("b账户增加100");
  62. //更新文档 将文档中likes=100的文档修改为likes=200
  63. collection.updateMany(session, Filters.eq("name", b), inc("money", money));
  64. }
  65. //带事务a减100
  66. private static void minusTransacFromA(ClientSession session, String a, int money) {
  67. System.out.println("a账户减少100");
  68. //inc 表示累加函数
  69. collection.updateMany(session, Filters.eq("name", a), inc("money", -money));
  70. }
  71. private static void printDataState() {
  72. //persons表示itcast数据库中的集合名
  73. collection = mongoDatabase.getCollection("account");
  74. System.out.println("数据库中的起始状态:");
  75. //检索所有文档
  76. /**
  77. * 1. 获取迭代器FindIterable<Document>
  78. * 2. 获取游标MongoCursor<Document>
  79. * 3. 通过游标遍历检索出的文档集合
  80. * */
  81. //1. 获取迭代器FindIterable<Document>
  82. FindIterable<Document> findIterable = collection.find();
  83. //2. 获取游标MongoCursor<Document>
  84. MongoCursor<Document> mongoCursor = findIterable.iterator();
  85. //3. 通过游标遍历检索出的文档集合
  86. while (mongoCursor.hasNext()) {
  87. System.out.println(mongoCursor.next());
  88. }
  89. }
  90. }

16.3. 聚合数据类型转换

https://www.runoob.com/mongodb/mongodb-replication.html

MongoDB4.0增加了一个新的聚合操作符:$convert,用来进行数据类型的转换。这个类型转换操作符简化了数据的抽取、转换和加载的过程。同时将客户端的处理数据的压力转移到了服务器端。从而减轻了客户端处理数据的压力。

  1. #from -- 转账发起人
  2. #to -- 转账接收人
  3. #time -- 转账时间
  4. #money -- 转账金额
  5. use itcast;
  6. var one = {"from":"a","to":"b","money":100};
  7. var two = {"from":"a","to":"b","money":200,"time":ISODate("2018-05-11T13:58:51.122Z")};
  8. var thr = {"from":"a","to":"b","money":300,"time":"2018-07-10 14:38:50"};
  9. var four = {"from":"a","to":"b","money":100,"time":"2017-04-16 14:38:50"};
  10. var five = {"from":"a","to":"b","money":500,"time":1569569092514};
  11. var six = {"from":"a","to":"b","money":500,"time":"Last Friday"};
  12. db.transfer.insertMany([one,two,thr,four,five,six]);

我们发现上述结果的时间每条转账记录都不一致。非常杂乱。有的转账记录是标准的例如ISODate,有的时间是字符串,有的是使用整数表示,而还有的根本没有转账记录。还有的时间是无效的。

那么这个时候我们就可以使用MongoDB4.0引入的数据类型转换的操作符来将转账时间统一为一致的数据类型。

  1. conversionStage={
  2. //聚合通道
  3. $project:{
  4. //在数据映射通道中保留原来的数据项,设置为1
  5. from:1,
  6. to:1,
  7. money:1,
  8. time:{//转账时间需要做一些类型的转换
  9. //转换操作符
  10. $convert:{
  11. //必须书写的 原来的转账时间
  12. input:"$time",
  13. //必须书写的 希望把这一项数据转换哪种类型,date就是mongo的标准时间类型ISODate
  14. to:"date",
  15. //onError这一项是可选的。对于存在的属性,但是属性值是完全没有办法转换为标准的日期格式,可以对其显示。
  16. onError:{
  17. //$concat表示字段拼接操作符
  18. $concat:["can not convert ",{$toString:"$time"}," to date type"]
  19. },
  20. //缺失转账时间这一项,可以对其提示
  21. onNull:"missing time"
  22. }
  23. }
  24. }
  25. };

使用聚合函数aggregate()处理上述数据。执行转换操作

  1. #db.集合名.aggregate([聚合操作内容])
  2. db.transfer.aggregate([conversionStage]);