• 学习 MongoDB5 这一篇就够了



    一、相关概念

    1.1、业务场景

    1、传统的关系型数据库 (比如 MySQL), 在数据操作的”三高”需求以及对应的 Web 2.0 网站需求面前, 会有”力不从心”的感觉

    所谓的三高需求:

    高并发, 高性能, 高可用, 简称三高

    • High Performance: 对数据库的高并发读写的要求
    • High Storage: 对海量数据的高效率存储和访问的需求
    • High Scalability && High Available: 对数据的高扩展性和高可用性的需求

    而 MongoDB 可以应对三高需求


    2、具体的应用场景:

    • 社交场景, 使用 MongoDB 存储存储用户信息, 以及用户发表的朋友圈信息, 通过地理位
    • 游戏场景, 使用 MongoDB 存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.
    • 物流场景, 使用 MongoDB 存储订单信息, 订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.
    • 物联网场景, 使用 MongoDB 存储所有接入的智能设备信息, 以及设备汇报的日志信息, 并对这些信息进行多维度的分析.
    • 视频直播, 使用 MongoDB 存储用户信息, 点赞互动信息等.

    3、这些应用场景中, 数据操作方面的共同点有:

    数据量大

    1. 写入操作频繁
    2. 价值较低的数据, 对事务性要求不高
    3. 对于这样的数据, 更适合用 MongoDB 来实现数据存储

    那么我们什么时候选择 MongoDB 呢?

    除了架构选型上, 除了上述三个特点之外, 还要考虑下面这些问题:

    • 应用不需要事务及复杂 JOIN 支持
    • 新应用, 需求会变, 数据模型无法确定, 想快速迭代开发
    • 应用需要 2000 - 3000 以上的读写QPS(更高也可以)
    • 应用需要 TB 甚至 PB 级别数据存储
    • 应用发展迅速, 需要能快速水平扩展
    • 应用要求存储的数据不丢失
    • 应用需要 99.999% 高可用
    • 应用需要大量的地理位置查询, 文本查询

    如果上述有1个符合, 可以考虑 MongoDB, 2个及以上的符合, 选择 MongoDB 绝不会后悔.


    1.2、简介

    MongoDB是一个开源, 高性能, 无模式的文档型数据库, 当初的设计就是用于简化开发和方便扩展, 是NoSQL数据库产品中的一种.是最 像关系型数据库(MySQL)的非关系型数据库.

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

    MongoDB中的记录是一个文档, 它是一个由字段和值对(field:value)组成的数据结构.MongoDB文档类似于JSON对象, 即一个文档认 为就是一个对象.字段的数据类型是字符型, 它的值除了使用基本的一些类型外, 还可以包括其他文档, 普通数组和文档数组


    1.3、体系结构

    在这里插入图片描述

    在这里插入图片描述


    1.4、数据模型

    在这里插入图片描述


    二、安装

    1、运行容器

    docker run --name mongodb \
    -p 27017:27017 \
    -v /mydata/mongodb/data:/data/db/mongo \
    -d mongo
    
    • 1
    • 2
    • 3
    • 4
    -e MONGO_INITDB_ROOT_USERNAME=root \
    -e MONGO_INITDB_ROOT_PASSWORD=laptoy \
    
    • 1
    • 2

    2、下载可视化 下载地址

    在这里插入图片描述

    3、连接

    在这里插入图片描述


    三、基本常用命令

    3.1、数据库操作

    默认保留的数据库

    • admin:从权限角度考虑, 这是 root 数据库, 如果将一个用户添加到这个数据库, 这个用户自动继承所有数据库的权限, 一些特定的服务器端命令也只能从这个数据库运行, 比如列出所有的数据库或者关闭服务器
    • local:数据永远不会被复制, 可以用来存储限于本地的单台服务器的集合 (部署集群, 分片等)
    • config:Mongo 用于分片设置时, config 数据库在内部使用, 用来保存分片的相关信息
    mongo --username=root --password=laptoy # 连接
    
    show dbs/databases; 
    
    use [dbname]; 	 	# 使用数据库,若不存在则创建
    
    • 1
    • 2
    • 3
    • 4
    • 5

    当使用 use articledb 的时候. articledb 其实存放在内存之中, 当 articledb 中存在一个 collection 之后, mongo 才会将这个数据库持久化到硬盘之中.

    db.dropDatabase() 	// 删除当前库
    
    • 1

    3.2、集合操作

    db.createCollection(name)
    
    show collections/tables
    
    db.[collectionName].drop()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


    3.3、文档基本CRUD

    插入文档若不存在集合默认隐式创建集合

    1、插入

    // 向集合中添加一个文档
    db.comment.insertOne(
    	{"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001",
    	"nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null}
    )
    
    db.comment.insertMany([
    	{"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
    	{"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
    	{"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
    	{"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
    	{"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}
    ]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    捕捉批量插入异常

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

    2、查询

    1、查询

    db.comment.find({参数},{投影})
    
    db.comment.find()
    
    db.comment.find({"userid":"1003"})  		// 根据articleid查询
    db.comment.findOne({"articleid":"xxx"})  	// 根据articleid查询第一条
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    2、投影查询

    db.comment.find({"articleid":"xxx"},{"articleid":1}) 			// 投影查询
    db.comment.find({"articleid":"xxx"},{"articleid":1,_id:0}) 		// 投影查询
    
    • 1
    • 2

    默认投影有_id

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


    3、更新

    db.collection.update(query, update, options)
    
    • 1

    1、覆盖修改

    如果我们想修改_id为1的记录,点赞量为1001,输入以下语句:

    db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
    
    • 1

    执行后,我们会发现,这条文档除了likenum字段其它字段都不见了


    2、局部修改

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

    3、批量修改

    更新所有用户为 1003 的用户的昵称为 凯撒大帝

    // 默认只修改第一条数据
    db.comment.update({userid:"1003"},{$set:{nickname:"凯撒大帝"}})
    // 修改所有符合条件的数据
    db.comment.update({userid:"1003"},{$set:{nickname:"凯撒大帝"}},{multi:true})
    
    • 1
    • 2
    • 3
    • 4

    4、列值增长的修改

    如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用 $inc 运算符来实现。

    需求:对3号数据的点赞数,每次递增1

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

    4、删除

    db.comment.remove(条件)
    
    db.comment.remove({_id:"1"})
    
    • 1
    • 2
    • 3

    3.4、分页查询

    1、统计查询

    db.comment.count()		// 统计所有记录
    
    db.comment.count({userid:"1003"}) // 按条件统计
    
    • 1
    • 2
    • 3

    2、limit()

    db.comment.find().limit(2)	// 查询前n条
    
    db.comment.find().limit(2).skip(2)	// 跳过前n条 查询前n条
    
    • 1
    • 2
    • 3

    3、排序查询

    sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列

    db.comment.find().sort({userid:-1,likenum:1})
    
    • 1

    3.5、更多查询

    1、正则表达式 查询

    db.collection.find({field:/正则表达式/})
    
    db.comment.find({content:/开水/})  // 查询评论内容包含“开水”的所有文档
    
    db.comment.find({content:/^专家/}) // 查询以专家开头的
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、比较查询

    db.集合名称.find({ "field" : { $gt: value }}) 	// 大于: field > value
    db.集合名称.find({ "field" : { $lt: value }}) 	// 小于: field < value
    db.集合名称.find({ "field" : { $gte: value }})	// 大于等于: field >= value
    db.集合名称.find({ "field" : { $lte: value }}) 	// 小于等于: field <= value
    db.集合名称.find({ "field" : { $ne: value }}) 	// 不等于: field != value
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、包含查询

    包含使用 $in 操作符。 示例:查询评论的集合中userid字段包含1003或1004的文档

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

    4、条件连接查询

    db.comment.find({$and:[
    	{likenum:{$gte:NumberInt(700)}},
    	{likenum:{$lt:NumberInt(2000)}}
    ]}) 
    
    • 1
    • 2
    • 3
    • 4
    db.comment.find({$or:[
    	{userid:"1003"},
    	{likenum:{$lt:1000}}
    ]})
    
    • 1
    • 2
    • 3
    • 4

    3.6、小结

    在这里插入图片描述


    四、索引

    4.1、概述

    索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

    如果查询存在适当的索引,MongoDB可以使用该索引限制必须检查的文档数。

    索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。

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


    4.2、类型

    1、单字段索引

    MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。

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

    在这里插入图片描述


    2、复合索引

    MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。

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

    在这里插入图片描述


    3、其他索引

    地理空间索引(Geospatial Index)、文本索引(Text Indexes)、哈希索引(Hashed Indexes)。

    • 地理空间索引(Geospatial Index)

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

    • 文本索引(Text Indexes)

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

    • 哈希索引(Hashed Indexes)

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


    4.3、管理操作

    1、索引的查看

    db.collection.getIndexes()
    
    • 1

    提示:该语法命令运行要求是MongoDB 3.0+

    结果中显示的是默认_id 索引:

    MongoDB在创建集合的过程中,在 id字段上创建一个唯一的索引,默认名字为_id,该索引可防止客户端插入两个具有相同值的文档,您不能在_id字段上删除此索引。

    注意:该索引是唯一索引,因此值不能重复,即_id值不能重复的。在分片集群中,通常使用_id 作为片键。


    2、创建索引

    db.collection.createIndex(keys,options)
    
    • 1

    单字段索引

    db.comment.createIndex({userid:-1})
    
    • 1

    复合索引

    db.comment.createIndex({userid:-1,nickname:-1})
    
    • 1

    3、删除索引

    db.collection.dropIndex(index)
    
    • 1

    删除 comment 集合中 userid 字段上的升序索引:

    db.comment.dropIndex({userid:-1})
    
    • 1

    删除所有索引

    db.comment.dropIndexes()
    
    • 1

    4.4、索引的使用

    1、执行计划

    分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。

    那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看。

    语法:

    db.collection.find(query,options).explain(options)
    
    • 1
    db.comment.find({userid:"1003"}).explain()
    
    • 1

    预先创建索引并通过索引查询的结果 2选

    在这里插入图片描述

    没有预先创建索引的结果 5选

    在这里插入图片描述


    4.5、涵盖的扫描

    当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果(不再去找集合),而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以非常有效。

    在这里插入图片描述

    db.comment.find({userid:"1003"},{userid:1,_id:0})
    
    • 1

    在这里插入图片描述


    五、整合Java案例:文章评论

    5.1、需求分析

    某头条的文章评论业务如下:

    在这里插入图片描述

    文章示例参考:早晨空腹喝水,是对还是错?https://www.toutiao.com/a6721476546088927748/

    需要实现以下功能:

    • 基本增删改查API
    • 根据文章id查询评论
    • 评论点赞

    5.2、表结构分析

    数据库:articledb

    专栏文章评论comment
    字段名称字段含义字段类型备注
    _idIDObjectId或StringMongo的主键字段
    articleid文章IDString
    content评论内容String
    userid评论人IDString
    nickname评论人昵称String
    createdatetime评论的日期时间Data
    likenum点赞数Int32
    replynum回复数Int32
    state状态String0:不可见;1:可见;
    parentid上级IDString如果为0表示文章的顶级评论

    5.3、技术选型

    1. mongodb-driver(了解)

    mongodb-driver是mongo官方推出的java连接mongoDB的驱动包,相当于JDBC驱动。我们通过一个入门的案例来了解mongodb-driver的基本使用。

    官方驱动说明和下载:http://mongodb.github.io/mongo-java-driver/

    官方驱动示例文档:http://mongodb.github.io/mongo-java-driver/3.8/driver/getting-started/quick-start/

    2. SpringDataMongoDB

    SpringData家族成员之一,用于操作MongoDB的持久层框架,封装了底层的mongodb-driver。

    官网主页: https://projects.spring.io/spring-data-mongodb/

    我们十次方项目的吐槽微服务就采用SpringDataMongoDB框架


    5.4、服务搭建

    1、搭建项目工程article,pom.xml引入依赖:

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-mongodbartifactId>
    dependency>
     <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、YML

    spring:
      data:
        mongodb:
          host: 120.76.55.xx
          port: 27017
          database: articledb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.5、实现增删改查

    1、实体类

    @Data
    @Document(collection = "comment")
    public class Comment implements Serializable {
    
        @Id
        private String id;
        @Field("content")                       // 该属性对应mongodb的字段的名字,如果一致,则无需该注解
        private String content;                 // 吐槽内容
        private Date publishtime;               // 发布日期
        @Indexed
        private String userid;                  // 发布人ID
        private String nickname;                // 昵称
        private LocalDateTime createdatetime;   // 评论的日期时间
        private Integer likenum;                // 点赞数
        private Integer replynum;               // 回复数
        private String state;                   // 状态
        private String parentid;                // 上级ID
        private String articleid;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2、mapper

    public interface CommentMapper extends MongoRepository<Comment, String> {
    }
    
    • 1
    • 2

    3、service

    @Service
    public class CommentService {
    
        @Autowired
        CommentMapper commentMapper;
    
        public void saveComment(Comment comment) {
            // 如果需要自定义主键,可以在这里指定主键;如果不指定主键,MongoDB会自动生成主键
            commentMapper.save(comment);
        }
    
        public void updateComment(Comment comment) {
            commentMapper.save(comment);
        }
    
        public void deleteCommentById(String id) {
            commentMapper.deleteById(id);
        }
    
        public List<Comment> findCommentList() {
            return commentMapper.findAll();
        }
    
        public Comment findCommentById(String id) {
            return commentMapper.findById(id).get();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4、测试

    @SpringBootTest
    class ArticleApplicationTests {
    
        @Autowired
        CommentService commentService;
    
        @Test
        public void testFindCommentById() {
            Comment commentById = commentService.findCommentById("1");
            System.out.println(commentById);
        }
    
        @Test
        public void testSaveComment() {
            Comment comment = new Comment(); // 不设置id默认雪花算法生成
            comment.setArticleid("100000");
            comment.setContent("测试添加的数据");
            comment.setCreatedatetime(LocalDateTime.now());
            comment.setUserid("1006");
            comment.setNickname("Laptoy");
            comment.setState("1");
            comment.setReplynum(0);
            comment.setReplynum(0);
            commentService.saveComment(comment);
        }
    
        @Test
        public void testFindCommentList() {
            System.out.println(commentService.findCommentList());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述


    5.6、根据上级ID查询文章评论的分页列表

    1、mapper新增

    //根据父id,查询子评论的分页列表
    Page<Comment> findByParentid(String parentid, Pageable pageable);
    
    • 1
    • 2

    2、service新增

    public Page<Comment> findCommentListByParentid(String parentid,int page,int size){
        return commentRepository.findByParentid(parentid, PageRequest.of(page-1,size));
    }
    
    • 1
    • 2
    • 3

    3、测试

    @Test
    public void testFindCommentListByParentid(){
        Page<Comment> pageResponse = commentService.findCommentListByParentid("3", 1, 2);
        System.out.println("---总记录数---:"+pageResponse.getTotalElements());
        System.out.println("---当前页数据---:"+pageResponse.getContent());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4、使用compass快速插入一条测试数据,数据的内容是对3号评论内容进行评论。

    在这里插入图片描述

    5、执行测试结果

    ---总记录数---:1
    ---当前页数据---:[Comment(id=62b86e74258c6f1903c71820, content=:不要让惰性毁了你, publishtime=null, userid=1003, nickname=null, createdatetime=null, likenum=null, replynum=null, state=null, parentid=3, articleid=100000)]
    
    • 1
    • 2

    5.7、评论点赞

    /**
     * 点赞-效率低
     * @param id
     */
    public void updateCommentThumbupToIncrementingOld(String id){
        Comment comment = commentRepository.findById(id).get();
        comment.setLikenum(comment.getReplynum()+1);
        commentRepository.save(comment);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    以上方法虽然实现起来比较简单,但是执行效率并不高,因为我只需要将点赞数加1就可以了,没必要查询出所有字段修改后再更新所有字段。(蝴蝶效应)

    我们可以使用MongoTemplate类来实现对某列的操作

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

    1、service

    @Autowired
    private MongoTemplate mongoTemplate;
    
    public void updataCommentLikenum(String id){
    
       //查询条件
       Query query = Query.query(Criteria.where("_id").is(id));
    
       //更新条件
       Update update = new Update();
    
       // 局部更新,相当于$set
       // update.set(key,value)
       // 递增$inc
       // update.inc("likenum",1);
       update.inc("likenum");
    
    
       //参数1:查询对象
       //参数2:更新对象
       //参数3:集合的名字或实体类的类型Comment.class
       mongoTemplate.updateFirst(query,update,Comment.class);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2、测试

    @Test
    public void testupdataCommentLikenum() {
        commentService.updataCommentLikenum("3");
    }
    
    • 1
    • 2
    • 3
    • 4

    六、集群和安全

    6.1、简介

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

    也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异 步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动 切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。

    1. 冗余和数据可用性

    复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别 的容错功能,以防止丢失单个数据库服务器。

    在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不 同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他 副本,例如灾难恢复,报告或备份。

    1. MongoDB中的复制

    副本集是一组维护相同数据集的mongod实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。 在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。

    主节点接收所有写操作。 副本集只能有一个主要能够确认具有{w:“most”}写入关注的写入; 虽然在某 些情况下,另一个mongod实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有 更改,即oplog。

    在这里插入图片描述

    辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据 集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。

    1. 主从复制和副本集区别

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


    6.2、副本集的两种类型三个角色

    两种类型:

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

    三种角色:

    • 主要成员(Primary):主要接收所有写操作。就是主节点。

    • 副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可 以读操作(但需要配置)。是默认的一种从节点类型。

    • 仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副 本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

    在这里插入图片描述

    关于仲裁者的额外说明:

    您可以将额外的mongod实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过 响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可 以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。

    如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用 硬件。

    仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要 人员。

    如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。

    如果你的副本+主节点的个数是奇数,可以不加仲裁者


    6.3、架构

    一主一副本一仲裁

    在这里插入图片描述


    6.4、副本集的创建

    1、创建主节点

    建立存放数据和日志的目录

    mkdir -p /mydata/mongodb/replica_sets/myrs_27017/log
    mkdir -p /mydata/mongodb/replica_sets/myrs_27017/data/db
    
    vim /mydata/mongodb/replica_sets/myrs_27017/mongod.conf
    
    • 1
    • 2
    • 3
    • 4
    systemLog:
      #MongoDB发送所有日志输出的目标指定为文件
      destination: file
      #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
      path: "/mongodb/replica_sets/myrs_27017/log/mongod.log"
      #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
      logAppend: true
    storage:
      #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
      dbPath: "/mongodb/replica_sets/myrs_27017/data/db"
      journal:
        #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
        enabled: true
    processManagement:
      #启用在后台运行mongos或mongod进程的守护进程模式。
      fork: true
      #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
      pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid"
    net:
      #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
      #bindIpAll: true
      #服务实例绑定的IP
      bindIp: localhost,172.24.18.186
      #bindIp
      #绑定的端口
      port: 27017
    replication:
      #副本集的名称
      replSetName: myrs
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    Java设计模式之访问者模式
    Django高级之-分页器
    众佰诚:抖音开网店新手怎么做才能做起来
    嵌入式学习--1线协议(以ds18b20为例)
    力扣(LeetCode)182. 查找重复的电子邮箱(2022.07.01)
    唯品会三年,我只做了5件事,如今跳槽天猫拿下offer(Java岗)
    苯丙氨酸甲酯双三氟甲基磺酰亚胺[PheC1][Tf2N]氨基酸酯离子液体
    Mac可以卸载掉系统自带的软件吗 Mac第三方软件无法卸载是为什么
    【JS】对象字面量 代替 switch 方法
    Linux内存管理 | 四、物理地址空间设计模型
  • 原文地址:https://blog.csdn.net/apple_53947466/article/details/127906389