【MongoDB】一问带你深入理解什么是MongDB,MongoDB超超详细保姆级教程

news2024/9/25 17:16:16

目录

  • 1、MongoDB概述
  • 2、MongoDB 主要特点
    • 2.1、文档
    • 2.2、集合
    • 2.3、数据库
    • 2.4、数据模型
  • 3、Windows安装MongoDB
    • 3.1、下载MongoDB
    • 3.2、安装MongoDB
    • 3.3、配置MongoDB
  • 4、Linux安装MongoDB
    • 4.1、下载MongoDB
    • 4.2、解压安装
    • 4.3、安装一个可视化工具
  • 5、MongoDB基本操作及增删改查
    • 5.1、基本操作
    • 5.2、增删改查
    • 5.3、修改文档
    • 5.4、删除文档
    • 5.5、总结
  • 6、MongoDB存储数据类型
    • 6.1、数字
    • 6.2、字符串
    • 6.3、正则表达式
    • 6.4、数组
    • 6.5、日期
    • 6.6、内嵌文档
  • 7、MongoDB 中的索引
    • 7.1、索引创建
    • 7.2、查看索引
    • 7.3、删除索引
    • 7.4、总结
  • 8、Java操作MongoDB
    • 8.1、方式一
      • 8.1.1、前期准备
      • 8.1.2、获取集合
    • 8.2、方式二
  • 9、MongoDB之副本集配置
    • 9.1、MongoDB主从复制
    • 9.2、MongoDB副本集
      • 9.2.1 配置副本集
      • 9.2.2 副本集测试
      • 9.2.3 开启安全认证

1、MongoDB概述

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

它支持的数据结构非常松散,是类似jsonbson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

MongoDB服务端可运行在LinuxWindows平台,支持32位64位应用,默认端口为27017

推荐运行在64位平台,因为MongoDB在32位模式运行时支持的最大文件尺寸为2GB

2、MongoDB 主要特点

2.1、文档

MongoDB中的记录是一个文档,它是由字段和值对组成的数据结构。
多个键及其关联的值有序地放在一起就构成了文档。
MongoDB文档类似于JSON对象。字段的值可以包括其他文档,数组和文档数组。

在这里插入图片描述

{“greeting”:“hello,world”}这个文档只有一个键“greeting”,对应的值为“hello,world”。多数情况下,文档比这个更复杂,它包含多个键/值对。

例如:{“greeting”:“hello,world”,“foo”: 3} 文档中的键/值对是有序的,下面的文档与上面的文档是完全不同的两个文档。{“foo”: 3 ,“greeting”:“hello,world”}

文档中的值不仅可以是双引号中的字符串,也可以是其他的数据类型,例如,整型、布尔型等,也可以是另外一个文档,即文档可以嵌套。文档中的键类型只能是字符串。

使用文档的优点是:

  • 文档(即对象)对应于许多编程语言中的本机数据类型
  • 嵌入式文档和数组减少了对昂贵连接的需求
  • 动态模式支持流畅的多态性

2.2、集合

集合就是一组文档,类似于关系数据库中的表。

集合是无模式的,集合中的文档可以是各式各样的。例如,{“hello,word”:“Mike”}{“foo”: 3},它们的键不同,值的类型也不同,但是它们可以存放在同一个集合中,也就是不同模式的文档都可以放在同一个集合中。

既然集合中可以存放任何类型的文档,那么为什么还需要使用多个集合?

这是因为所有文档都放在同一个集合中,无论对于开发者还是管理员,都很难对集合进行管理,而且这种情形下,对集合的查询等操作效率都不高。所以在实际使用中,往往将文档分类存放在不同的集合中。
例如,对于网站的日志记录,可以根据日志的级别进行存储,Info级别日志存放在Info 集合中,Debug 级别日志存放在Debug 集合中,这样既方便了管理,也提供了查询性能。

但是需要注意的是,这种对文档进行划分来分别存储并不是MongoDB 的强制要求,用户可以灵活选择。

可以使用“.”按照命名空间将集合划分为子集合。

例如,对于一个博客系统,可能包括blog.userblog.article 两个子集合,这样划分只是让组织结构更好一些,blog 集合和blog.userblog.article 没有任何关系。虽然子集合没有任何特殊的地方,但是使用子集合组织数据结构清晰,这也是MongoDB 推荐的方法。

2.3、数据库

MongoDB 中多个文档组成集合,多个集合组成数据库。

一个MongoDB 实例可以承载多个数据库。它们之间可以看作相互独立,每个数据库都有独立的权限控制。在磁盘上,不同的数据库存放在不同的文件中。

MongoDB 中存在以下系统数据库。

  • Admin 数据库:一个权限数据库,如果创建用户的时候将该用户添加到admin 数据库中,那么该用户就自动继承了所有数据库的权限。
  • Local 数据库:这个数据库永远不会被复制,可以用来存储本地单台服务器的任意集合。
  • Config 数据库:当MongoDB 使用分片模式时,config 数据库在内部使用,用于保存分片的信息。

2.4、数据模型

一个MongoDB 实例可以包含一组数据库,一个DataBase 可以包含一组Collection(集合),一个集合可以包含一组Document(文档)。

一个Document包含一组field(字段),每一个字段都是一个key/value pair

  • key: 必须为字符串类型
  • value:可以包含如下类型
    • 基本类型,例如,string,int,float,timestamp,binary 等类型
    • 一个document
    • 数组类型

3、Windows安装MongoDB

3.1、下载MongoDB

MongoDB提供了可用于32位系统和64位系统的预编译二进制包(新版本没有了32位系统的安装文件),你可以进入MongoDB官网下载安装,MongoDB的预编译二进制包的下载地址为:https://www.mongodb.com/download-center/community,打开之后会看到如下图,直接点击Download下载即可,也可以在Version中选择你想要的版本:

在这里插入图片描述

3.2、安装MongoDB

双击打开文件进行安装,在安装过程中,可以通过点击 “Custom(自定义)” 按钮来设置你的安装目录。

在这里插入图片描述

这里我选择安装在E:\MongoDB这个目录下(安装目录会影响我们后面的配置)

在这里插入图片描述

这里选择直接next

在这里插入图片描述

这里安装 "Install MongoDB Compass" 不勾选,否则可能要很长时间都一直在执行安装,MongoDB Compass是一个图形界面管理工具,这里不安装也是没有问题的,可以自己去下载一个图形界面管理工具,比如Robo3T

在这里插入图片描述

之后稍微等待一会就安装好了。

3.3、配置MongoDB

MongoDB的安装过程是很简单的,但是配置就比较麻烦了,可能会遇到各种各样的问题,需要你有足够的耐心和仔细。

首先要在MongoDBdata文件夹里新建一个db文件夹和一个log文件夹

在这里插入图片描述

然后在log文件夹下新建一个mongo.log

在这里插入图片描述
然后将E:\MongoDB\bin添加到环境变量path中,此时打开cmd窗口运行一下mongo命令,出现如下情况:

在这里插入图片描述
这是为什么呢?这是因为我们还没有启动MongoDB服务,自然也就连接不上服务了。那要怎么启动呢?在cmd窗口中运行如下命令:

 mongod --dbpath E:\MongoDB\data\db

需要注意的是:如果你没有提前创建db文件夹,是无法启动成功的。运行成功之后,我们打开浏览器,输入127.0.0.1:27017,看到如下图,就说明MongoDB服务已经成功启动了。

在这里插入图片描述

但是如果每次都要这么启动服务的话也太麻烦了吧,这里你可以选择设置成开机自启动,也可以选择用命令net start mongodb来手动启动,这里我选择使用后者,具体方法如下。

还是打开cmd窗口,不过这次是以管理员身份运行,然后输入如下命令:

mongod --dbpath "E:\MongoDB\data\db" --logpath "E:\MongoDB\data\log\mongo.log" -install -serviceName "MongoDB"

如果没有报错的话就说明成功添加到服务里了,可以使用win+R然后输入services.msc命令进行查看:

在这里插入图片描述

默认是自动运行的,这里我选择把它改成手动的。然后在cmd窗口中运行net start mongodb

在这里插入图片描述
怎么解决呢?两个步骤:
1)运行sc delete mongodb删除服务;
2)再运行一次配置服务的命令:

mongod --dbpath "E:\MongoDB\data\db" --logpath "E:\MongoDB\data\log\mongo.log" -install -serviceName "MongoDB"

然后再运行net start mongodb,服务启动成功:

在这里插入图片描述

可能遇到的问题:
1、mongod不是内部或外部命令
出现这种问题说明你没有把bin目录添加到环境变量之中,重新添加一下即可解决。

2、服务名无效
首先是看你输入的服务名称是否有误,然后再查看本地服务中有没有MongoDB服务,如果没有服务,则运行命令添加服务即可。

3、发生服务特定错误:100
删除db文件夹下的mongod.lockstorage.bson两个文件,若删除完之后仍然出现这种问题,用sc delete mongodb删除服务,再配置一下服务就能解决了。

4、Linux安装MongoDB

4.1、下载MongoDB

官方下载地址:https://www.mongodb.com/download-center/community

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.1.tgz

在这里插入图片描述

4.2、解压安装

1、解压

tar -zxvf mongodb-linux-x86_64-rhel70-4.2.1.tgz

2、创建目录/usr/local/mongo,并将解压完的mongodb目录移动到/usr/local/mongo下

mkdir -p /usr/local/mongo
mv mongodb-linux-x86_64-rhel70-4.2.1/* /usr/local/mongo/ 

3、切到/usr/local/mongo目录下,创建目录

mkdir -p data/db        #数据库目录
mkdir -p logs           #日志目录
mkdir -p conf           #配置文件目录
mkdir -p pids           #进程描述文件目录

创建好的目录如下:

在这里插入图片描述

4、在conf目录,增加配置文件mongo.conf

vi /usr/local/mongo/conf/mongo.conf
#数据保存路径
dbpath=/usr/local/mongo/data/db/
#日志保存路径
logpath=/usr/local/mongo/logs/mongo.log
#进程描述文件
pidfilepath=/usr/local/mongo/pids/mongo.pid
#日志追加写入
logappend=true
bind_ip_all=true
#mongo默认端口
port=27017
#操作日志容量
oplogSize=10000
#开启子进程
fork=true

5、通过配置文件启动mongo服务端

/usr/local/mongo/bin/mongod -f /usr/local/mongo/conf/mongo.conf

启动成功如下:

在这里插入图片描述

6、启动mongo客户端

/usr/local/mongo/bin/mongo --host 127.0.0.1 --port 27017

启动成功如下:

在这里插入图片描述

至此安装完成~

4.3、安装一个可视化工具

官网下载 RoBo 3T(Robomongo is now Robo 3T)
下载地址:https://robomongo.org/download

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

双击安装包安装,修改安装路径,不停下一步,点击安装。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样就连接成功,adminconfiglocal是默认数据库;

连接成功后,右击服务器,选择Add Database,创建数据库

在这里插入图片描述

创建数据库firstTest,然后右击firstTest,选择open Shell,开始进行shell命令来创建数据库中的集合和文档。

在这里插入图片描述

在这里插入图片描述

5、MongoDB基本操作及增删改查

5.1、基本操作

登陆数据库

mongo

查看数据库

show databases;

在这里插入图片描述

选择数据库
use 数据库名

在这里插入图片描述
如果切换到一个没有的数据库,例如use admin2,那么会隐式创建这个数据库。(后期当该数据库有数据时,系统自动创建)

use admin2

在这里插入图片描述

查看集合

show collections

在这里插入图片描述

创建集合

db.createCollection('集合名')

在这里插入图片描述

删除集合

`db.集合名.drop()`

在这里插入图片描述

删除数据库
通过use语法选择数据
通过db.dropDataBase()删除数据库

在这里插入图片描述

5.2、增删改查

增加

db.集合名.insert(JSON数据)

如果集合存在,那么直接插入数据。如果集合不存在,那么会隐式创建。

示例:在test2数据库的c1集合中插入数据(姓名叫Hanson年龄18岁)

use test2 
db.c1.insert({uname:"Hanson",age:18})
  • 数据库和集合不存在都隐式创建
  • 对象的键统一不加引号(方便看),但是查看集合数据时系统会自动加
  • mongodb会给每条数据增加一个全球唯一的_id键

在这里插入图片描述

  • _id键的组成

在这里插入图片描述

  • 自己增加_id
    可以,只需要给插入的JSON数据增加_id键即可覆盖(但实战强烈不推荐
db.c1.insert({_id:1, uname:"Hanson", age:18})

在这里插入图片描述

一次性插入多条数据

传递数据,数组中写一个个JSON数据即可

db.c1.insert([     {uname:"张3", age:3},     {uname:"李4", age:4},     {uname:"王5", age:5} ])

在这里插入图片描述

快速插入10条数据

由于mongodb底层使用JS引擎实现的,所以支持部分js语法。因此:可以写for循环

for (var i=1; i<=10; i++) {     db.c2.insert({uanme: "a"+i, age: i}) }

在这里插入图片描述
查询文档

db.集合名.find(条件[,查询的列])
条件写法
查询所有的数据{}或者不写
查询age=6的数据{age:6}
既要age=6又要性别=男{age:6,sex:‘男’}

在这里插入图片描述

查询的列(可选参数)写法
查询全部列(字段)不写
只显示age列(字段){age:1}
除了age列(字段)都显示{age:0}

其他语法

db.集合名.find({
        键:{运算符:值}
        })
运算符作用
$gt大于
$gte大于等于
$lt小于
$lte小于等于
$ne不等于
$inin
$ninnot in

实例练习

查询所有数据

db.c1.find()

在这里插入图片描述
系统的_id无论如何都会存在

1、查询age大于5的数据

db.c1.find({age:{$gt:5}})

在这里插入图片描述

2、查询年龄是5岁8岁10岁的数据

db.c2.find({age:{$in:[5,8,10]}})

在这里插入图片描述
3、只看年龄列,或者年龄以外的列

在这里插入图片描述

5.3、修改文档

db.集合名.update(条件,新数据[是否新增,是否修改多条,])
  • 新数据此数据需要使用修改器,如果不使用,那么会将新数据替换原来的数据。db.集合名.update(条件,{修改器:{键:值}}[是否新增,是否修改多条,])
    修改器作用inc递增rename重命名列set修改列值unset删除列

  • 是否新增
    指条件匹配不到数据则插入(true是插入,false否不插入默认)
    db.c3.update({uname:"Hanson30"},{$set:{age:30}},true)

在这里插入图片描述

  • 是否修改多条
    指将匹配成功的数据都修改(true是,false否默认)
    db.c3.update({uname:"Hanson2"},{$set:{age:30}},false,true)

实例练习

准备工作

use test2;
for(var i = 1; i<= 10; i++){
	db.c3.insert( {"uname":"Hanson"+i,"age":i} );
}

在这里插入图片描述

1、将{uname:“Hanson1”}改为{uname:“Hanson2”}

db.c3.update({uname:"Hanson1"},{$set:{uname:"Hanson2"}})

在这里插入图片描述

2、给{uname:"Hanson10"}的年龄加2岁减2岁

db.c3.update({uname:"Hanson10"},{$inc:{age:2}})

在这里插入图片描述
递减只需要将2改为-2即可。

综合练习插入数据:

db.c4.insert( {uname:"神龙教主",age:888,who:"男",other:"非国人"});

5.4、删除文档

db.集合名.remove(条件[,是否删除一条])
  • 是否删除一条
    true:是(删除的数据为第一条)
    false:否

在这里插入图片描述

db.c3.remove({uname:"Hanson3"})

在这里插入图片描述

5.5、总结

高级开发攻城狮统称:所有数据库都需要增删改查CURD标识

MongoDB删除语法:remove

Create

db.集合名.insert(JSON数据)

Delete

db.集合名.remove(条件 [,是否删除一条true是false否默认])

也就是默认删除多条

Update

db.集合名.update(条件, 新数据  [,是否新增,是否修改多条])

升级语法db.集合名.update(条件,{修改器:{键:值}})

Read

db.集合名.find(条件 [,查询的列])

6、MongoDB存储数据类型

MongoDB中每条记录称作一个文档,这个文档和我们平时用的JSON有点像,但也不完全一样。JSON是一种轻量级的数据交换格式。简洁和清晰的层次结构使得JSON成为理想的数据交换语言,JSON易于阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率,但是JSON也有它的局限性,比如它只有null、布尔、数字、字符串、数组和对象这几种数据类型,没有日期类型只有一种数字类型,无法区分浮点数和整数,也没法表示正则表达式或者函数由于这些局限性,BSON闪亮登场啦,BSON是一种类JSON的二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象但是BSON有JSON没有的一些数据类型,如DateBinData类型,MongoDB使用BSON做为文档数据存储和网络传输格式。

6.1、数字

shell默认使用64位浮点型数值,如下:

db.sang_collec.insert({x:3.1415926})
db.sang_collec.insert({x:3})

对于整型值,我们可以使用NumberInt或者NumberLong表示,如下:

db.sang_collec.insert({x:NumberInt(10)})
db.sang_collec.insert({x:NumberLong(12)})

在这里插入图片描述

6.2、字符串

字符串也可以直接存储,如下:

db.sang_collec.insert({x:"hello MongoDB!"})

6.3、正则表达式

正则表达式主要用在查询里边,查询时我们可以使用正则表达式,语法和JavaScript中正则表达式的语法相同,比如查询所有keyxvaluehello开始的文档且不区分大小写:

db.sang_collec.find({x:/^(hello)(.[a-zA-Z0-9])+/i})

在这里插入图片描述

6.4、数组

数组一样也是被支持的,如下:

db.sang_collec.insert({x:[1,2,3,4,new Date()]})

数组中的数据类型可以是多种多样的。

6.5、日期

MongoDB支Date类型的数据,可以直接new一个Date对象,如下:

db.sang_collec.insert({x:new Date()})

在这里插入图片描述

6.6、内嵌文档

一个文档也可以作为另一个文档的value,这个其实很好理解,如下:

db.sang_collect.insert({name:"三国演义",author:{name:"罗贯中",age:99}});

书有一个属性是作者,作者又有name,年龄等属性。

在这里插入图片描述

7、MongoDB 中的索引

7.1、索引创建

默认情况下,集合中的_id字段就是索引,我们可以通过getIndexes()方法来查看一个集合中的索引:

db.sang_collect.getIndexes()

结果如下:

[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "sang.sang_collect"
    }
]

我们看到这里只有一个索引,就是_id

现在我的集合中有10000个文档,我想要查询x1的文档,我的查询操作如下:

db.sang_collect.find({x:1})

这种查询默认情况下会做全表扫描,我们可以用上篇文章介绍的explain()来查看一下查询计划,如下:

db.sang_collect.find({x:1}).explain("executionStats")

结果如下:

{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test2.sang_collect",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"x" : {
				"$eq" : 1
			}
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"filter" : {
				"x" : {
					"$eq" : 1
				}
			},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 1,
		"executionTimeMillis" : 0,
		"totalKeysExamined" : 0,
		"totalDocsExamined" : 1000,
		"executionStages" : {
			"stage" : "COLLSCAN",
			"filter" : {
				"x" : {
					"$eq" : 1
				}
			},
			"nReturned" : 1,
			"executionTimeMillisEstimate" : 0,
			"works" : 1002,
			"advanced" : 1,
			"needTime" : 1000,
			"needYield" : 0,
			"saveState" : 7,
			"restoreState" : 7,
			"isEOF" : 1,
			"direction" : "forward",
			"docsExamined" : 1000
		}
	},
	"serverInfo" : {
		"host" : "iZuf6280jydzscf9ukffswZ",
		"port" : 27017,
		"version" : "4.2.1",
		"gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e"
	},
	"ok" : 1
}

我们可以看到查询方式是全表扫描,一共扫描了10000个文档才查出来我要的结果。实际上我要的文档就排第二个,但是系统不知道这个集合中一共有多少个x为1的文档,所以会把全表扫描完,这种方式当然很低效,但是如果我加上 limit,如下

db.sang_collect.find({x:1}).limit(1)

在这里插入图片描述

此时再看查询计划发现只扫描了两个文档就有结果了,但是如果我要查询x9999的记录,那还是得把全表扫描一遍,此时,我们就可以给该字段建立索引,索引建立方式如下:

db.sang_collect.ensureIndex({x:1})

1表示升序,-1表示降序。当我们给x字段建立索引之后,再根据x字段去查询,速度就非常快了,我们看下面这个查询操作的执行计划:

db.sang_collect.find({x:9999}).explain("executionStats")

这个查询计划过长我就不贴出来了,我们可以重点关注查询要耗费的时间大幅度下降。

此时调用getIndexes()方法可以看到我们刚刚创建的索引,如下:

[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "sang.sang_collect"
    },
    {
        "v" : 2,
        "key" : {
            "x" : 1.0
        },
        "name" : "x_1",
        "ns" : "sang.sang_collect"
    }
]

我们看到每个索引都有一个名字,默认的索引名字为字段名_排序值,当然我们也可以在创建索引时自定义索引名字,如下:

db.sang_collect.ensureIndex({x:1},{name:"myfirstindex"})

此时创建好的索引如下:

{
    "v" : 2,
    "key" : {
        "x" : 1.0
    },
    "name" : "myfirstindex",
    "ns" : "sang.sang_collect"
}

当然索引在创建的过程中还有许多其他可选参数,如下:

db.sang_collect.ensureIndex({x:1},{name:"myfirstindex",dropDups:true,background:true,unique:true,sparse:true,v:1,weights:99999})

关于这里的参数,我说一下:

  1. name表示索引的名称
  2. dropDups表示创建唯一性索引时如果出现重复,则将重复的删除,只保留第一个
  3. background是否在后台创建索引,在后台创建索引不影响数据库当前的操作,默认为false
  4. unique是否创建唯一索引,默认false
  5. sparse对文档中不存在的字段是否不起用索引,默认false
  6. v表示索引的版本号,默认为2
  7. weights表示索引的权重

此时创建好的索引如下:

{
    "v" : 1,
    "unique" : true,
    "key" : {
        "x" : 1.0
    },
    "name" : "myfirstindex",
    "ns" : "sang.sang_collect",
    "background" : true,
    "sparse" : true,
    "weights" : 99999.0
}

7.2、查看索引

getIndexes()可以用来查看索引,我们还可以通过totalIndexSize()来查看索引的大小,如下:

db.sang_collect.totalIndexSize()

7.3、删除索引

我们可以按名称删除索引,如下:

db.sang_collect.dropIndex("xIndex")

表示删除一个名为xIndex的索引,当然我们也可以删除所有索引,如下:

db.sang_collect.dropIndexes()

7.4、总结

索引是个好东西,可以有效的提高查询速度,但是索引会降低插入、更新和删除的速度,因为这些操作不仅要更新文档,还要更新索引,MongoDB 限制每个集合上最多有64个索引,我们在创建索引时要仔细斟酌索引的字段。

8、Java操作MongoDB

8.1、方式一

方式一采用的原生Java操作MongoDB

8.1.1、前期准备

首先我们需要驱动,MongoDBJava驱动我们可以直接在Maven中央仓库去下载,也可以创建Maven工程添加如下依赖:

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver</artifactId>
    <version>3.5.0</version>
</dependency>

建议通过Maven来添加依赖,如果自己下载jar,需要下载如下三个jar:

1.org.mongodb:bson:jar:3.5.0
2.org.mongodb:mongodb-driver-core:jar:3.5.0
3.org.mongodb:mongodb-driver:jar:3.5.0

在这里插入图片描述

另外,在使用Java操作MongoDB之前,记得启动 MongoDB

8.1.2、获取集合

所有准备工作完成之后,我们首先需要一个MongoClient,如下:

MongoClient client = new MongoClient("192.168.248.136", 27017);

然后通过如下方式获取一个数据库,如果要获取的数据库本身就存在,直接获取到,不存在MongoDB会自动创建:

MongoDatabase sang = client.getDatabase("sang");

然后通过如下方式获取一个名为c1的集合,这个集合存在的话就直接获取到,不存在的话MongoDB会自动创建出来,如下:

MongoCollection<Document> c = sang.getCollection("c1");

有了集合之后,我们就可以向集合中插入数据了。

1、增加操作

和在shell中的操作一样,我们可以一条一条的添加数据,也可以批量添加,添加单条数据操作如下:

Document d1 = new Document();
d1.append("name", "三国演义").append("author", "罗贯中");
c.insertOne(d1);

添加多条数据的操作如下:

List<Document> collections = new ArrayList<Document>();
Document d1 = new Document();
d1.append("name", "三国演义").append("author", "罗贯中");
collections.add(d1);
Document d2 = new Document();
d2.append("name", "红楼梦").append("author", "曹雪芹");
collections.add(d2);
c.insertMany(collections);

当然也可以通过 Robo 3T查看修改结果:db.集合名.find()

2、修改操作

可以修改查到的第一条数据,操作如下:

c.updateOne(Filters.eq("author", "罗贯中"), new Document("$set", new Document("name", "三国演义123")));

上例中小伙伴们也看到了修改器要如何使用,不管是inc,用法都一致,我这里不再一个一个演示。也可以修改查到的所有数据,如下:

c.updateMany(Filters.eq("author", "罗贯中"), new Document("$set", new Document("name", "三国演义456")));

3、删除操作

可以删除查到的一条数据,如下:

c.deleteOne(Filters.eq("author", "罗贯中"));

也可以删除查到的所有数据:

c.deleteMany(Filters.eq("author", "罗贯中"));

Filters里边还有其他的查询条件,都是见名知意,不赘述。

4、 查询操作

可以直接查询所有文档:

FindIterable<Document> documents = c.find();
MongoCursor<Document> iterator = documents.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

也可以按照条件查询:

FindIterable<Document> documents = c.find(Filters.eq("author", "罗贯中"));
MongoCursor<Document> iterator = documents.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

其他的方法基本都是见名知意,这里不再赘述。

5、验证问题

上面我们演示的获取一个集合是不需要登录MongoDB数据库的,如果需要登录,我们获取集合的方式改为下面这种:

ServerAddress serverAddress = new ServerAddress("192.168.248.128", 27017);
List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();
MongoCredential mc = MongoCredential.createScramSha1Credential("Hanson","sang_collect","123".toCharArray());
credentialsList.add(mc);
MongoClient client = new MongoClient(serverAddress,credentialsList);
MongoDatabase sang = client.getDatabase("sang_collect");
c = sang.getCollection("c1");

MongoCredential是一个凭证,第一个参数为用户名,第二个参数是要在哪个数据库中验证,第三个参数是密码的char数组,然后将登录地址封装成一个ServerAddress,最后将两个参数都传入MongoClient中实现登录功能。

6、其他配置

在连接数据库的时候也可以设置连接超时等信息,在MongoClientOptions中设置即可,设置方式如下:

ServerAddress serverAddress = new ServerAddress("192.168.248.128", 27017);
List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();
MongoCredential mc = MongoCredential.createScramSha1Credential("rwuser","sang","123".toCharArray());
credentialsList.add(mc);
MongoClientOptions options = MongoClientOptions.builder()
        //设置连接超时时间为10s
        .connectTimeout(1000*10)
        //设置最长等待时间为10s
        .maxWaitTime(1000*10)
        .build();
MongoClient client = new MongoClient(serverAddress,credentialsList,options);
MongoDatabase sang = client.getDatabase("sang");
c = sang.getCollection("c1");

8.2、方式二

主要讲解SpringBoot操作MongoDB实现增删改查的功能,代码GitHub

1、pom.xml引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2、创建application.yml

spring:
  data:
    mongodb:
      host: 192.168.72.129
      database: studentdb

3、创建实体类

创建包com.hanson.mongodb,包下建包pojo 用于存放实体类,创建实体类

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serializable;

/**
 * @author hanson
 * @date 2024/3/28 18:14
 */
@Document(collection = "student")
public class Student implements Serializable {

    @Id
    private Long id;

    private String name;

    private String sex;

    private String age;

    private String introduce;

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getIntroduce() {
        return introduce;
    }

    public void setIntroduce(String introduce) {
        this.introduce = introduce;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

4、创建数据访问接口com.hanson.mongodb包下创建dao包,包下创建接口

import com.hanson.mongodb.pojo.Student;

import java.util.List;

/**
 * @author hanson
 * @date 2024/3/28 18:17
 */
public interface StudentDao {


    void save(Student student);

    void update(Student student);

    List<Student> findAll();

    void delete(Integer id);
}

5、创建业务逻辑类com.hanson.mongodb包下创建impl包,包下创建类

import com.hanson.mongodb.dao.StudentDao;
import com.hanson.mongodb.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author hanson
 * @date 2024/3/28 18:19
 */
@Component
public class StudentDaoImpl implements StudentDao {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 新增信息
     * @param student
     */
    @Override
    public void save(Student student) {
        mongoTemplate.save(student);
    }

    /**
     * 修改信息
     * @param student
     */
    @Override
    public void update(Student student) {
        //修改的条件
        Query query = new Query(Criteria.where("id").is(student.getId()));

        //修改的内容
        Update update = new Update();
        update.set("name",student.getName());

        mongoTemplate.updateFirst(query,update,Student.class);
    }

    /**
     * 查询所有信息
     * @return
     */
    @Override
    public List<Student> findAll() {
        return mongoTemplate.findAll(Student.class);
    }

    /**
     * 根据id查询所有信息
     * @param id
     */
    @Override
    public void delete(Integer id) {
        Student byId = mongoTemplate.findById(1,Student.class);
        mongoTemplate.remove(byId);
    }

}

6、创建测试类

import com.hanson.mongodb.dao.StudentDao;
import com.hanson.mongodb.pojo.Student;
import org.junit.jupiter.api.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.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
class MongodbDemoApplicationTests {

    @Autowired
    private StudentDao studentDao;

    /**
     * 查询所有信息
     */
    @Test
    public void findAll() {
        List<Student> all = studentDao.findAll();
        System.out.println(all.size());
        System.out.println("Students:");
        for (Student student : all) {
            System.out.println("Name: " + student.getName() + ", Id: " + student.getId());
        }
    }

    /**
     * 新增信息
     */
    @Test
    public void save() {
        Student student = new Student();
        student.setId(6l);
        student.setName("张三");
        studentDao.save(student);
    }

    /**
     * 修改信息
     */
    @Test
    public void update() {
        Student student = new Student();
        student.setId(2l);
        student.setName("李四");
        studentDao.update(student);
    }

    /**
     * 删除信息
     */
    @Test
    public void delete() {
        studentDao.delete(6);
    }
}

在这里插入图片描述

9、MongoDB之副本集配置

9.1、MongoDB主从复制

主从复制是MongoDB最早使用的复制方式, 该复制方式易于配置,并且可以支持任意数量的从节点服务器,与使用单节点模式相比有如下

优点:

在从服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。

可配置读写分离,主节点负责写操作,从节点负责读操作,将读写压力分开,提高系统的稳定性。

在这里插入图片描述
MongoDB 的主从复制至少需要两个服务器或者节点。其中一个是主节点,负责处理客户端请求,其它的都是从节点,负责同步主节点的数据。

主节点记录在其上执行的所有写操作,从节点定期轮询主节点获取这些操作,然后再对自己的数据副本执行这些操作。由于和主节点执行了相同的操作,从节点就能保持与主节点的数据同步。

主节点的操作记录称为oplog(operation log),它被存储在 MongoDB local 数据库中。oplog 中的每个文档都代表主节点上执行的一个操作。需要重点强调的是oplog只记录改变数据库状态的操作。比如,查询操作就不会被存储在oplog中。这是因为oplog只是作为从节点与主节点保持数据同步的机制。

然而,主从复制并非生产环境下推荐的复制方式,主要原因如下两点:

1、灾备都是完全人工的 如果主节点发生故障失败,管理员必须关闭一个从服务器,然后作为主节点重新启动它。然后应用程序必须重新配置连接新的主节点。
2、数据恢复困难 因为oplog只在主节点存在,故障失败需要在新的服务器上创建新的oplog,这意味着任意存在的节点需要重新从新的主节点同步oplog。

因此,在新版本的MongoDB中已经不再支持使用主从复制这种复制方式了,取而代之的是使用副本集复制方式。

9.2、MongoDB副本集

MongoDB副本集(Replica Set)其实就是具有自动故障恢复功能的主从集群,和主从复制最大的区别就是在副本集中没有固定的“主节点;整个副本集会选出一个节点作为“主节点”,当其挂掉后,再在剩下的从节点中选举一个节点成为新的“主节点”,在副本集中总有一个主节点(primary)和一个或多个备份节点(secondary)

除了primarysecondary之外,副本集中的节点还可以是以下角色:

成为primary对客户端可见参与投票延迟同步复制数据
Default
Secondary-Only
Hidden
Delayed
Arbiters
Non-Voting

官方推荐的副本集最小配置需要有三个节点:一个主节点接收和处理所有的写操作,两个备份节点通过复制主节点的操作来对主节点的数据进行同步备份。

在这里插入图片描述

9.2.1 配置副本集

1、环境准备

副本集各节点IP如下:

172.16.250.234
172.16.250.239
172.16.250.240

首先,先对三个MongoDB 节点进行安装。

然后,依次修改各个节点的 mongodb.conf 配置文件,增加副本集相关配置,内容如下:

dbpath=/usr/local/mongodb-4.0.2/data
logpath=/usr/local/mongodb-4.0.2/log/mongodb.log
fork=true
logappend=true
bind_ip= # 此处填写服务器的IP
port=27017

# 设置副本集名称,在各个配置文件中,其值必须相同
replSet=rs0

配置完成之后,分别在三个节点上执行如下命令通过加载文件配置来启动MongoDB服务:

mongod -config /usr/local/mongodb-4.0.2/mongodb.conf
# 或者
mongod -f /usr/local/mongodb-4.0.2/mongodb.conf

至此,3个MongoDB实例都已经以副本集方式启动,但它们彼此之间现在还不会进行通信,仍需要进行一些配置。

2、副本集初始化

通过Shell连接到任意一个MongoDB实例,执行rs.initiate()方法对副本集进行初始化。

[root@hadoop34 mongodb-4.0.2]# mongo 172.16.250.234:27017
> conf=
    {
    "_id" : "rs0",
    "members" : [
        { "_id" : 0, "host" : "172.16.250.234:27017" },
        { "_id" : 1, "host" : "172.16.250.239:27017" },
        { "_id" : 2, "host" : "172.16.250.240:27017" }
        ]
    }
> rs.initiate(conf)
{
    "ok" : 1,
    "operationTime" : Timestamp(1542247326, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1542247326, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}
rs0:SECONDARY>

如果在执行rs.initiate()方法时不传入任何参数,MongoDB 将以默认的配置文档对副本集进行初始化,后续可以再通过rs.add()方法来向副本集中添加成员。

3、副本集更新

# 向副本集中添加成员
rs.add("172.16.250.240:27017")
 
# 从副本集中删除成员
rs.remove("172.16.250.240:27017")
 
# 向副本集中添加仲裁
rs.addArb("172.16.250.240:27017")
 
# 向副本集中添加备份节点
rs.add({"_id":3,"host":"172.16.250.240:27017","priority":0,"hidden":true})
# 更改副本集配置
rs0:PRIMARY> var conf=rs.conf()
rs0:PRIMARY> conf.members[1].priority = 5
 
# PRIMARY节点上执行如下命令
rs0:PRIMARY> rs.reconfig(conf)
{
    "ok" : 1,
    "operationTime" : Timestamp(1542248518, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1542248518, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}
 
# SECONDARY节点上执行如下命令,需增加 force 参数
rs0:SECONDARY> rs.reconfig(conf,{force:true})
{
    "ok" : 1,
    "operationTime" : Timestamp(1542248726, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1542248726, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

例如,强制让一个节点成为Primary,可以将该节点的优先级设置成最高。

cfg = rs.conf()
cfg.members[0].priority = 5
cfg.members[1].priority = 1
cfg.members[2].priority = 1
rs.reconfig(cfg)

4、副本集监控

# 查看副本集的配置信息
rs0:PRIMARY> rs.conf()
{
    "_id" : "rs0",
    "version" : 104658,
    "protocolVersion" : NumberLong(1),
    "writeConcernMajorityJournalDefault" : true,
    "members" : [
    {
        "_id" : 0,
        "host" : "172.16.250.234:27017",
        "arbiterOnly" : false,
        "buildIndexes" : true,
        "hidden" : false,
        "priority" : 1,
        "tags" : {},
        "slaveDelay" : NumberLong(0),
        "votes" : 1
    },
    {
        "_id" : 1,
        "host" : "172.16.250.239:27017",
        "arbiterOnly" : false,
        "buildIndexes" : true,
        "hidden" : false,
        "priority" : 5,
        "tags" : {},
        "slaveDelay" : NumberLong(0),
        "votes" : 1
    },
    {
        "_id" : 2,
        "host" : "172.16.250.240:27017",
        "arbiterOnly" : false,
        "buildIndexes" : true,
        "hidden" : false,
        "priority" : 1,
        "tags" : {},
        "slaveDelay" : NumberLong(0),
        "votes" : 1
    }],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {},
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("5becd39e360189766762e057")
    }
}
# 查看副本集运行状态
rs0:PRIMARY> rs.status()
{
    "set" : "rs0",
    "date" : ISODate("2018-11-15T02:46:15.138Z"),
    "myState" : 1,
    "term" : NumberLong(2),
    "syncingTo" : "",
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        }
    },
    "lastStableCheckpointTimestamp" : Timestamp(1542249916, 1),
    "members" : [
    {
        "_id" : 0,
        "name" : "172.16.250.234:27017",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 2651,
        "optime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "optimeDate" : ISODate("2018-11-15T02:46:06Z"),
        "optimeDurableDate" : ISODate("2018-11-15T02:46:06Z"),
        "lastHeartbeat" : ISODate("2018-11-15T02:46:13.520Z"),
        "lastHeartbeatRecv" : ISODate("2018-11-15T02:46:13.519Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "172.16.250.239:27017",
        "syncSourceHost" : "172.16.250.239:27017",
        "syncSourceId" : 1,
        "infoMessage" : "",
        "configVersion" : 104658
        },
    {
        "_id" : 1,
        "name" : "172.16.250.239:27017",
        "health" : 1,
        "state" : 1,
        "stateStr" : "PRIMARY",
        "uptime" : 2799,
        "optime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "optimeDate" : ISODate("2018-11-15T02:46:06Z"),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "infoMessage" : "",
        "electionTime" : Timestamp(1542248524, 1),
        "electionDate" : ISODate("2018-11-15T02:22:04Z"),
        "configVersion" : 104658,
        "self" : true,
        "lastHeartbeatMessage" : ""
    },
    {
        "_id" : 2,
        "name" : "172.16.250.240:27017",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 1855,
        "optime" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1542249966, 1),
            "t" : NumberLong(2)
        },
        "optimeDate" : ISODate("2018-11-15T02:46:06Z"),
        "optimeDurableDate" : ISODate("2018-11-15T02:46:06Z"),
        "lastHeartbeat" : ISODate("2018-11-15T02:46:13.520Z"),
        "lastHeartbeatRecv" : ISODate("2018-11-15T02:46:13.520Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "172.16.250.239:27017",
        "syncSourceHost" : "172.16.250.239:27017",
        "syncSourceId" : 1,
        "infoMessage" : "",
        "configVersion" : 104658
    }],
    "ok" : 1,
    "operationTime" : Timestamp(1542249966, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1542249966, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}
# 查看备份节点的复制信息
rs0:PRIMARY> db.printSlaveReplicationInfo()
source: 172.16.250.234:27017
    syncedTo: Thu Nov 15 2018 11:08:36 GMT+0800 (CST)
    0 secs (0 hrs) behind the primary
source: 172.16.250.240:27017
    syncedTo: Thu Jan 01 1970 08:00:00 GMT+0800 (CST)
    1542251316 secs (428403.14 hrs) behind the primary

9.2.2 副本集测试

Primary 上插入一万条客户数据:

rs0:PRIMARY> for(var i=0;i<10000;i++){db.customer.insert({"name":"user"+i})}
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.customer.count()
10000

Secondary上查看客户数据是否已经同步:

rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> db.customer.count()
10000

故障转移测试

执行如下命令关闭Primary节点,查看其他2个节点的情况:

mongod --shutdown --dbpath /usr/local/mongodb-4.0.2/data
# 查看Primary节点关闭之前的状态
rs0:PRIMARY> rs.status()
{
    "set" : "rs0",
    "date" : ISODate("2018-11-15T03:36:31.393Z"),
    "myState" : 1,
    "term" : NumberLong(4),
    "syncingTo" : "",
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        }
    },
    "lastStableCheckpointTimestamp" : Timestamp(1542252978, 1),
    "members" : [
    {
        "_id" : 0,
        "name" : "172.16.250.234:27017",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 425,
        "optime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "optimeDate" : ISODate("2018-11-15T03:36:28Z"),
        "optimeDurableDate" : ISODate("2018-11-15T03:36:28Z"),
        "lastHeartbeat" : ISODate("2018-11-15T03:36:31.243Z"),
        "lastHeartbeatRecv" : ISODate("2018-11-15T03:36:30.233Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "172.16.250.239:27017",
        "syncSourceHost" : "172.16.250.239:27017",
        "syncSourceId" : 1,
        "infoMessage" : "",
        "configVersion" : 104666
    },
    {
        "_id" : 1,
        "name" : "172.16.250.239:27017",
        "health" : 1,
        "state" : 1,
        "stateStr" : "PRIMARY",
        "uptime" : 428,
        "optime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "optimeDate" : ISODate("2018-11-15T03:36:28Z"),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "infoMessage" : "",
        "electionTime" : Timestamp(1542252577, 2),
        "electionDate" : ISODate("2018-11-15T03:29:37Z"),
        "configVersion" : 104666,
        "self" : true,
        "lastHeartbeatMessage" : ""
    },
    {
        "_id" : 2,
        "name" : "172.16.250.240:27017",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 78,
        "optime" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1542252988, 1),
            "t" : NumberLong(4)
        },
        "optimeDate" : ISODate("2018-11-15T03:36:28Z"),
        "optimeDurableDate" : ISODate("2018-11-15T03:36:28Z"),
        "lastHeartbeat" : ISODate("2018-11-15T03:36:31.376Z"),
        "lastHeartbeatRecv" : ISODate("2018-11-15T03:36:29.597Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "172.16.250.239:27017",
        "syncSourceHost" : "172.16.250.239:27017",
        "syncSourceId" : 1,
        "infoMessage" : "",
        "configVersion" : 104666
    }],
    "ok" : 1,
    "operationTime" : Timestamp(1542252988, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1542252988, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}
# 在任意其他节点上查看Primary节点关闭之后的状态
> rs.status()
{
    "set" : "rs0",
    "date" : ISODate("2018-11-15T03:41:31.213Z"),
    "myState" : 1,
    "term" : NumberLong(5),
    "syncingTo" : "",
    "syncSourceHost" : "",
    "syncSourceId" : -1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1542253290, 1),
            "t" : NumberLong(5)
        },
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1542253290, 1),
            "t" : NumberLong(5)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1542253290, 1),
            "t" : NumberLong(5)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1542253290, 1),
            "t" : NumberLong(5)
        }
    },
    "lastStableCheckpointTimestamp" : Timestamp(1542253268, 1),
    "members" : [
    {
        "_id" : 0,
        "name" : "172.16.250.234:27017",
        "health" : 1,
        "state" : 1,
        "stateStr" : "PRIMARY",
        "uptime" : 6115,
        "optime" : {
            "ts" : Timestamp(1542253290, 1),
            "t" : NumberLong(5)
        },
        "optimeDate" : ISODate("2018-11-15T03:41:30Z"),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "infoMessage" : "could not find member to sync from",
        "electionTime" : Timestamp(1542253288, 1),
        "electionDate" : ISODate("2018-11-15T03:41:28Z"),
        "configVersion" : 104666,
        "self" : true,
        "lastHeartbeatMessage" : ""
    },
    {
        "_id" : 1,
        "name" : "172.16.250.239:27017",
        "health" : 0,
        "state" : 8,
        "stateStr" : "(not reachable/healthy)",
        "uptime" : 0,
        "optime" : {
            "ts" : Timestamp(0, 0),
            "t" : NumberLong(-1)
        },
        "optimeDurable" : {
            "ts" : Timestamp(0, 0),
            "t" : NumberLong(-1)
        },
        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
        "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
        "lastHeartbeat" : ISODate("2018-11-15T03:41:30.593Z"),
        "lastHeartbeatRecv" : ISODate("2018-11-15T03:41:18.148Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "Error connecting to 172.16.250.239:27017 :: caused by ::     Connection refused",
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "infoMessage" : "",
        "configVersion" : -1
    },
    {
        "_id" : 2,
        "name" : "172.16.250.240:27017",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 372,
        "optime" : {
            "ts" : Timestamp(1542253268, 1),
            "t" : NumberLong(4)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1542253268, 1),
            "t" : NumberLong(4)
        },
        "optimeDate" : ISODate("2018-11-15T03:41:08Z"),
        "optimeDurableDate" : ISODate("2018-11-15T03:41:08Z"),
        "lastHeartbeat" : ISODate("2018-11-15T03:41:30.591Z"),
        "lastHeartbeatRecv" : ISODate("2018-11-15T03:41:31.106Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "infoMessage" : "",
        "configVersion" : 104666
    }],
    "ok" : 1,
    "operationTime" : Timestamp(1542253290, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1542253290, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

再次启动172.16.250.239:27017节点,由于其选举优先级最高,自动被选举为Primary。

# 待172.16.250.239:27017 节点启动后再次查看副本集状态
> rs.status()
{
	"set" : "rs0",
	"date" : ISODate("2018-11-15T03:44:01.745Z"),
	"myState" : 2,
	"term" : NumberLong(6),
	"syncingTo" : "172.16.250.239:27017",
	"syncSourceHost" : "172.16.250.239:27017",
	"syncSourceId" : 1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1542253435, 1),
			"t" : NumberLong(6)
		},
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1542253435, 1),
			"t" : NumberLong(6)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1542253435, 1),
			"t" : NumberLong(6)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1542253435, 1),
			"t" : NumberLong(6)
		}
	},
	"lastStableCheckpointTimestamp" : Timestamp(1542253400, 1),
	"members" : [
		{
			"_id" : 0,
			"name" : "172.16.250.234:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 6265,
			"optime" : {
				"ts" : Timestamp(1542253435, 1),
				"t" : NumberLong(6)
			},
			"optimeDate" : ISODate("2018-11-15T03:43:55Z"),
			"syncingTo" : "172.16.250.239:27017",
			"syncSourceHost" : "172.16.250.239:27017",
			"syncSourceId" : 1,
			"infoMessage" : "",
			"configVersion" : 104666,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 1,
			"name" : "172.16.250.239:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 23,
			"optime" : {
				"ts" : Timestamp(1542253435, 1),
				"t" : NumberLong(6)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1542253435, 1),
				"t" : NumberLong(6)
			},
			"optimeDate" : ISODate("2018-11-15T03:43:55Z"),
			"optimeDurableDate" : ISODate("2018-11-15T03:43:55Z"),
			"lastHeartbeat" : ISODate("2018-11-15T03:44:01.228Z"),
			"lastHeartbeatRecv" : ISODate("2018-11-15T03:44:00.835Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1542253424, 1),
			"electionDate" : ISODate("2018-11-15T03:43:44Z"),
			"configVersion" : 104666
		},
		{
			"_id" : 2,
			"name" : "172.16.250.240:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 522,
			"optime" : {
				"ts" : Timestamp(1542253435, 1),
				"t" : NumberLong(6)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1542253435, 1),
				"t" : NumberLong(6)
			},
			"optimeDate" : ISODate("2018-11-15T03:43:55Z"),
			"optimeDurableDate" : ISODate("2018-11-15T03:43:55Z"),
			"lastHeartbeat" : ISODate("2018-11-15T03:44:01.166Z"),
			"lastHeartbeatRecv" : ISODate("2018-11-15T03:44:01.414Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "172.16.250.239:27017",
			"syncSourceHost" : "172.16.250.239:27017",
			"syncSourceId" : 1,
			"infoMessage" : "",
			"configVersion" : 104666
		}
	],
	"ok" : 1,
	"operationTime" : Timestamp(1542253435, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1542253435, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

9.2.3 开启安全认证

创建用户

登录 PRIMARY节点创建用户,在此我们对test库开启安全认证。

rs0:PRIMARY> show dbs
admin   0.000GB
config  0.000GB
local   0.002GB
test    0.000GB
rs0:PRIMARY> use admin
switched to db admin
rs0:PRIMARY> db.createUser({user:"root",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
Successfully added user: {
	"user" : "root",
	"roles" : [
		{
			"role" : "userAdminAnyDatabase",
			"db" : "admin"
		}
	]
}
rs0:PRIMARY> use test
switched to db test
rs0:PRIMARY> db.createUser({user:"admin",pwd:"admin",roles:[{role:"readWrite",db:"test"}]})
Successfully added user: {
	"user" : "admin",
	"roles" : [
		{
			"role" : "readWrite",
			"db" : "test"
		}
	]
}

创建keyFile文件

先停掉所有SECONDARY节点的MongoDB服务,然后再停掉PRIMARY节点的MongoDB服务,并在PRIMARY节点所在服务器上创建keyFile文件。

[root@hadoop39 mongodb-4.0.2]# openssl rand -base64 666 > /usr/local/mongodb-4.0.2/keyfile
[root@hadoop39 mongodb-4.0.2]# chmod 600 /usr/local/mongodb-4.0.2/keyfile

将生成的keyFile文件拷贝到其他节点服务器上,并修改文件的操作权限为 600

chmod 600 /usr/local/mongodb-4.0.2/keyfile

更新启动配置文件
修改PRIMARY节点的 mongodb.conf 文件,增加如下内容:

# Add below Config
auth=true
oplogSize=100
keyFile=/usr/local/mongodb-4.0.2/keyfile

修改SECONDARY节点的 mongodb.conf 文件,增加如下内容:

# Add below Config
oplogSize=100
keyFile=/usr/local/mongodb-4.0.2/keyfile

启动副本集

先以 --auth 方式启动PRIMARY节点:

[root@hadoop39 mongodb-4.0.2]# mongod -f /usr/local/mongodb-4.0.2/mongodb.conf

再启动SECONDARY节点:

mongod -f /usr/local/mongodb-4.0.2/mongodb.conf

登录测试

[root@hadoop39 mongodb-4.0.2]# mongo -uadmin -padmin 172.16.250.239:27017
MongoDB shell version v4.0.2
connecting to: mongodb://172.16.250.239:27017/test
MongoDB server version: 4.0.2
rs0:PRIMARY> show dbs;
test 0.000GB

admin用户只能看到test库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1551594.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构进阶篇 之 【二叉树链序存储】的整体实现讲解

封建迷信我嗤之以鼻&#xff0c;财神殿前我长跪不起 一、二叉树链式结构的实现 1.二叉树的创建 1.1 手动创建 1.2 前序递归创建 2.二叉树的遍历 2.1 前序&#xff0c;中序以及后序遍历概念 2.2 层序遍历概念 2.3 前序打印实现 2.4 中序打印实现 2.4 后序打印实现 2.…

YOLOv9改进策略 :neck优化 | 路径融合GFPN,小目标到大目标一网打尽 | 轻骨干重Neck的轻量级目标检测器GiraffeDet

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;设计了一种新的路径融合GFPN&#xff1a;包含跳层与跨尺度连接&#xff0c;改进思路来自ICLR2022 GiraffeDet的核心思想。 &#x1f4a1;&#x1f4a1;&#x1f4a1;GFPN和六个检测头结合&#xff0c;这种跳层…

Git命令及GUI基本操作

不习惯使用Git命令的可移步下面Git GUI基本操作 Git 常用命令 git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git branch -a 查看所有的分支 git branch -r 查看本地所有分支 git commit -am "init" 提交并且加注释 git remote add orig…

20个超实用Python魔法方法

大家好&#xff01;今天我们要一起探索Python世界的神秘角落——那些被称为“魔法方法”的特殊成员方法。它们就像是编程中的魔法咒语&#xff0c;赋予你的类各种神奇特性&#xff0c;让你的代码更加简洁、强大且有趣味&#xff01; __init__&#xff1a;这是每个对象出生时都要…

Python爬虫实战—探索某网站电影排名

文章目录 Python爬虫实战—探索某网站电影排名准备工作编写爬虫代码代码解析运行情况截图进一步优化和说明完整代码总结 说明&#xff1a;本案例以XXX网站为例&#xff0c;已隐去具体网站名称与地址。 Python爬虫实战—探索某网站电影排名 网络爬虫是一种自动化程序&#xff0…

多线程的学习1

多线程 线程是操作系统能够进入运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 进程&#xff1a;是程序的基本执行实体。 并发&#xff1a;在同一个时刻&#xff0c;有多个指令在单个CPU上交替执行。 并行&#xff1a;在同一时刻&#xff0c…

js改变图片曝光度(高亮度)

方法一&#xff1a; 原理&#xff1a; 使用canvas进行滤镜操作&#xff0c;通过改变图片数据每个像素点的RGB值来提高图片亮度。 缺点 当前项目使用的是svg&#xff0c;而不是canvas 调整出来的效果不是很好&#xff0c;图片不是高亮&#xff0c;而是有些发白 效果 代码 …

OC对象 - Block解决循环引用

文章目录 OC对象 - Block解决循环引用前言1. 循环引用示例1.1 分析 2. 解决思路3. ARC下3.1 __weak3.2 __unsafe_unretained3.3 __block 4. MRC下4.1 __unsafe_unretain....4.1 __block 5. 总结5.1 ARC下5.2 MRC下 OC对象 - Block解决循环引用 前言 本章将会通过一个循环引用…

GitHub如何验证2FA,烦人的认证,看完几分钟解锁

序言 今天需要使用GitHub&#xff0c;还是不能用&#xff0c;需要2FA认证&#xff0c;没办法&#xff0c;还是让2FA认证流程来&#xff0c;一一解决&#xff0c;在解决这认证问题之前&#xff0c;先说说2FA认证是什么&#xff1f; 什么是2FA 2FA 是指两步验证&#xff08;Two…

用搜索引擎收集信息-常用方式

1&#xff0c;site csdn.net &#xff08;下图表示只在csdn网站里搜索java&#xff09; 2&#xff0c;filetype:pdf &#xff08;表示只检索某pdf文件类型&#xff09; 表示在浏览器里面查找有关java的pdf文件 3&#xff0c;intitle:花花 &#xff08;表示搜索网页标题里面有花…

【小尘送书-第十五期】Excel函数与公式应用大全for Excel 365 Excel

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…

python--初学函数

函数&#xff08;function&#xff09;&#xff1a; 什么是函数&#xff1f; 具有名称的&#xff0c;是为了解决某一问题&#xff0c;功能代码的集合&#xff0c;叫做函数 python中函数如何定义&#xff1a;def>define function定义函数 def function_name([args临时变量…

【QA】MySQL多表查询详解

文章目录 前言关系型数据库中数据表之间的关系数据准备数据内容表间关系 基础查询 | 全部查询多表查询分类1 | 连接查询内连接外连接 | 左外连接外连接 | 右外连接自连接 | 自连接自连接 | 联合查询 分类2 | 子查询返回结果分类 | 标量子查询返回结果分类 | 列子查询返回结果分…

linux centos7中使用 Postfix 和Dovecot搭建邮件系统

作者主页&#xff1a;点击&#xff01; Linux专栏&#xff1a;点击&#xff01; Postfix Postfix是一个开源的邮件传输代理&#xff08;MTA&#xff09;&#xff0c;用于路由和传送电子邮件。它是一个可靠、安全且高性能的邮件服务器软件&#xff0c;常用于搭建邮件系统的核心…

redis简介及常用命令

一、关系数据库与非关系型数据库 1.1、关系型数据库 一个结构化的数据库&#xff0c;创建在关系模型基础上一般面向于记录包括&#xff1a;Oracle、MySQL、SQL Server、Microsoft Access、DB2等以上数据库在使用的时候必须先建库建表设计表结构&#xff0c;然后存储数据的时候…

centos7系统下nginx1.24.0升级

如果没有这些目录&#xff0c;请先创建: mkdir /data/software mkdir /data/program提前下载所需的软件&#xff1a; cd /data/software wget https://ftp.pcre.org/pub/pcre/pcre-8.42.tar.gz wget https://nginx.org/download/nginx-1.24.0.tar.gz安装nginx cd /data/soft…

AM5SE系列微机保护装置在临沂奥体中心配电工程中的应用

摘 要&#xff1a;目前&#xff0c;微机保护装置广泛应用于电力系统中&#xff0c;该类装置能够有效监测电力系统的运行状况&#xff0c;并实时记录电力系统出现故障的位置及性质&#xff0c;从而为故障的快速处理提供有效的参考信息。本文介绍的AM5SE系列微机保护装置可以针对…

PCL点云处理之M估计样本一致性(MSAC)平面拟合(二百三十六)

PCL点云处理之M估计样本一致性(MSAC)平面拟合(二百三十五六) 一、算法介绍二、使用步骤1.代码2.效果一、算法介绍 写论文当然用RANSAC的优化变种算法MSAC啊,RANSAC太土太LOW了哈哈 MSAC算法(M-estimator Sample Consensus)是RANSAC(Random Sample Consensus)的一种…

【华大 HC32L110】调用`printf`和串口接收中断的冲突问题解决

华大单片机 HC32L110调用printf和串口接收中断的冲突问题解决,经过查找是官方库 去使能了 串口的接收功能,记录解决问题的过程 目录 1.硬件MCU资料2. printf和串口接收中断的冲突解决3.重新封装 fputc 函数4.查找问题,发现是官方库配置有误5. 查找寄存器手册,修改寄存器配置…

Discord账号多开如何做?有什么办法可以同时在线?

Discord 是一款免费的语音和文本聊天应用程序。它是一个游戏聊天应用程序和社区&#xff0c;最初是游戏的语音和IM服务&#xff0c;然后转向直播&#xff0c;然后是游戏商店的社区平台。它成为游戏玩家在游戏中交流和协作的首选工具。下面将为你介绍如何同时使用多个discord账号…