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

目录

  • 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.mfbz.cn/a/496739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【案例·增】获取当前时间、日期(含,SQL中DATE数据类型)

问题描述&#xff1a; 需要使用当前时间、日期&#xff0c;可以使用 SQL 中的 CURDATE() 、NOW()、CURTIME()运算符 案例&#xff1a; INSERT INTO table_name(current_time, column_name2,...) VALUES (NOW(),, ...)规则(Date 相关函数)&#xff1a; 规则(Date数据类型)

构建一个包含mvn命令的Java 17基础镜像

前言 官方提供的openjdk基础镜像&#xff0c;不包含mvn命令&#xff0c;无法用容器来打包代码。 在官方提供的镜像基础上安装maven。 前期准备&#xff0c;需要安装好docker。 一、安装maven 1、下载openjdk基础镜像&#xff0c;执行如下代码。 docker pull openjdk:17-j…

19. 变量

文章目录 一、变量二、变量的定义格式 一、变量 变量&#xff1a;程序中临时存储数据的容器&#xff0c;在程序执行过程中&#xff0c;其值有可能发生改变的量&#xff08;数据&#xff09;。但是这个容器中只能存一个值。 应用场景&#xff1a;在我们登录页面的时候&#xf…

JavaSE day14笔记

第十四天课堂笔记 课上: 适当做笔记课下 : 总结 , 读代码 , 反复敲代码 , 做练习 数组★★★ 数组 : 存储多个 同一类型 的容器格式 :数组类型 : 引用数据类型, new运算符在堆中 分配一块连续的存储空间 , 系统会给数组元素默认初始化 , 将该数组的引用赋值给数组名 引用数据…

3月28号总结

java学习 1.this关键字 this关键字可以代表当前对象的引用。它可以在类的方法中使用&#xff0c;用于引用调用该方法的对象。通过this关键字&#xff0c;可以访问类的成员变量和方法&#xff0c;以及调用其他构造函数。 举一个实例来学习一下this关键字的作用。 比如&#…

【unity】如何汉化unity Hub

相信大家下载安装unity后看着满操作栏的英文&#xff0c;英文不好的小伙伴们会一头雾水。但是没关系你要记住你要怎么高速运转的机器进入中国&#xff0c;请记住我给出的原理&#xff0c;不懂不代表不会用啊。现在我们就来把编译器给进行汉化。 第一步&#xff1a;我们打开Uni…

QT控件之显示控件

Qt Designer显示窗口部件提供的面板中&#xff0c;提供了10种显示小部件 &#xff08;1&#xff09; Label标签 &#xff08;2&#xff09; Text Browser文本浏览器 &#xff08;3&#xff09; Graphics View图形视图 &#xff08;4&#xff09; Calendar Widget日历 &…

IU5507低功耗DC-DC降压稳压器

IU5507T是一款由基准电压源、振荡电路、比较器、PWM/PFM 控制电路等构成的 CMOS 降压DC/DC调整器。利用 PWM/PFM 自动切换控制电路达到可调占空比&#xff0c;具有全输入电压范围(3-18V)内的低纹波、高效率和大输出电流等特点。 IU5507T内置功率MOSFET&#xff0c;使用过压、过…

libVLC 捕获鼠标、键盘事件

在实现播放器的时候&#xff0c;我们需要捕获键盘、鼠标事件进行视频快进、快退&#xff0c;或者双击全屏/退出全屏窗口、鼠标右键弹出菜单栏。默认情况下&#xff0c;在使用libVLC库的时候&#xff0c;我们无法捕获这些事件&#xff0c;因为我们将Qt的视频窗口传递给了libVLC。…

损坏的RAID5csp

1.解题思路 这道题太抽象了&#xff0c;一开始都没太搞懂在讲啥。。。解决该题需要了解条带、磁盘号的定义。 下图以样例2&#xff0c;输入编号为5的块为例&#xff1a; 请务必加上ios::sync_with_stdio(false),否则会超时只有30分 2.满分代码 #include<iostream> us…

Hbase 王者荣耀数据表 HBase常用Shell命令

大数据课本&#xff1a; HBase常用Shell命令 在使用具体的Shell命令操作HBase数据之前&#xff0c;需要首先启动Hadoop&#xff0c;然后再启动HBase&#xff0c;并且启动HBase Shell&#xff0c;进入Shell命令提示符状态&#xff0c;具体命令如下&#xff1a; $ cd /usr/local…

Hello算法2:复杂度分析

Hello算法2&#xff1a;复杂度分析 本文是基于k神的Hello 算法的读书笔记&#xff0c;请支持实体书。 https://www.hello-algo.com/chapter_paperbook/ 算法效率 算法效率评估 设计算法时&#xff0c;我们追求以下两个目标&#xff1a; 找出解法找出最优解 最优解通常包含…

Douyin视频详情数据API接口(视频详情,评论)

抖音官方并没有直接提供公开的视频详情数据采集API接口给普通用户或第三方开发者。抖音的数据采集通常受到严格的限制&#xff0c;以保护用户隐私和平台安全。 请求示例&#xff0c;API接口接入Anzexi58 如果您需要获取抖音视频详情数据&#xff0c;包括评论、点赞等&#xff…

VMware虚拟机更换引导顺序

前言 我用wmware装了黑群晖测试&#xff0c;将img转成vmdisk的格式之后发现系统引导盘之后1G&#xff0c;有点太小了 我准备把wmware的黑群晖系统迁移到新添加的虚拟磁盘里 1.登录黑群晖的SSH 请先在黑群晖的控制面板中的终端机和SNMP里面启用SSH功能&#xff0c;才能使用ss…

创新指南|如何将人工智能应用于未来的创新管理——并不断付诸实践

ChatGPT 的推出加剧了围绕人工智能的炒作&#xff0c;现在我们看到了前所未有的巨大进展。对于我们这些热衷于创新的人来说&#xff0c;这是一个激动人心的时刻。他们正在共同采取措施&#xff0c;充分利用人工智能进行创新管理。本文将阐述人工智能能为创新管理做什么&#xf…

《米小圈动画汉字》—“动起来”汉字就能轻松记住啦!

为了迎合孩子们的兴趣&#xff0c;市面上推出了许多类型的动画片&#xff0c;所谓“动画”是让角色动起来&#xff0c;感染孩子&#xff0c;给孩子带来欢乐。但是&#xff0c;并不是所有动画片都对孩子有益&#xff0c;市面上的大多良莠不齐&#xff0c;孩子分辨不了还可能影响…

2020年天津市二级分类土地利用数据(矢量)

天津市&#xff0c;位于华北平原海河五大支流汇流处&#xff0c;东临渤海&#xff0c;北依燕山。地势以平原和洼地为主&#xff0c;北部有低山丘陵&#xff0c;海拔由北向南逐渐下降&#xff0c;地貌总轮廓为西北高而东南低。天津有山地、丘陵和平原三种地形&#xff0c;平原约…

代码随想录算法训练营三刷day37 | 贪心 之 738.单调递增的数字 968.监控二叉树

三刷day37 738.单调递增的数字968.监控二叉树确定遍历顺序如何隔两个节点放一个摄像头情况1&#xff1a;左右节点都有覆盖情况2&#xff1a;左右节点至少有一个无覆盖的情况情况3&#xff1a;左右节点至少有一个有摄像头情况4&#xff1a;头结点没有覆盖 738.单调递增的数字 题…

中国国际通信大会2024|中国通信展览会|通信展览会

中国国际通信大会2024|中国通信展览会|通信展览会 中国国际信息通信展览会&#xff08;ICT展&#xff09;是亚太地区最具影响力的信息通信技术盛会之一。每年一度的ICT展汇聚了来自全球各行各业的专业人士&#xff0c;为各领域的科技公司、创新企业以及技术爱好者们提供一个难得…

VS2022 使用ClaudiaIDE设置自定义图片背景

ClaudiaIDE的下载 第一步&#xff0c;如下图所示&#xff0c;点击&#xff1a;扩展——管理扩展。 第二步&#xff0c;如下图所示&#xff0c;点击&#xff1a;联机——右上角输入ClaudiaIDE搜索——点击下载。 下载后关闭所有VS窗口&#xff0c;然后等待弹出一个安装窗口&…
最新文章