NoSQL - MongoDB - 学习/实践

1.应用场景

主要用于学习MongoDB,以及应用场景, 同时对比与关系型数据库如:MySQL,以及其他NoSQL的区别,总结思考。

应用场景还是比较多的「只要结合其优势,然后结合场景来判断是否适合」--- 最大的好处,是非结构化的文档存储方式

MongoDB都有哪些使用的业务场景 - 腾讯云开发者社区-腾讯云

1.应用服务器的日志记录

2.第三方信息的抓取与存储

3.运维监控系统

4.O2O业务场景

5.游戏业务场景「王者荣耀就是」

6.社交业务场景「使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。」

7.物联网业务场景「使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。」

8.视频直播业务场景「视频直播,使用 MongoDB 存储用户信息、礼物信息等。」

2.学习/操作

1. 文档阅读

MongoDB是什么?

Getting Started — MongoDB Manual

缓存服务的更新策略有哪些?

MongoDB 教程 | 菜鸟教程 -- 推荐快速学习

2. 整理输出

文章提纲:

1、MongoDB是什么?

2、为什么要使用MongoDB?

3、主要特性

4、C/S服务模型

5、完善的命令行工具

6、安装MongoDB

7、工具安装使用「命令行工具和可视化工具」

8、几个shell实操

9、代码中操作「在Java中使用 和 PHP中操作MongoDB 」

1、MongoDB是什么?

MongoDB 是一个基于分布式文件存储的数据库「没错MongoDB就是数据库,是NoSQL类型的数据库」

由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案,是一款为web应用程序和互联网基础设施设计的数据库管理系统。

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

从命名便可知:

MongoDB -- DB 结尾,定位就是数据库

而Memcached -- cache,则是定位就是缓存

2、为什么要用MongoDB?

(1) MongoDB提出的是文档、集合的概念,使用BSON(类JSON)作为其数据模型结构,其结构是面向对象的而不是二维表,存储一个用户在MongoDB中是这样子的。

{
    username: '123',
    password: '123'
}

使用这样的数据模型,使得MongoDB能在生产环境中提供高读写的能力,吞吐量较于mysql等SQL数据库大大增强。

(2) 易伸缩,自动故障转移。

易伸缩指的是提供了分片能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。自动故障转移是副本集的概念,MongoDB能检测主节点是否存活,当失活时能自动提升从节点为主节点,达到故障转移。

(3) 数据模型因为是面向对象的,所以可以表示丰富的、有层级的数据结构。

比如,博客系统中能把“评论”直接怼到“文章“的文档中,而不必像myqsl一样创建三张表来描述这样的关系。

3、主要特性

(1) 文档数据类

SQL类型的数据库是正规化的,可以通过主键或者外键的约束保证数据的完整性与唯一性,所以SQL类型的数据库常用于对数据完整性较高的系统。

MongoDB在这一方面是不如SQL类型的数据库,且MongoDB没有固定的Schema,正因为MongoDB少了一些这样的约束条件,可以让数据的存储数据结构更灵活,存储速度更加快。

(2) 即时查询能力

MongoDB保留了关系型数据库即时查询的能力,保留了索引(底层是基于B tree)的能力。这一点汲取了关系型数据库的优点,相比于同类型的NoSQL redis 并没有上述的能力。

(3) 复制能力

MongoDB自身提供了副本集能将数据分布在多台机器上实现冗余,目的是可以提供自动故障转移、扩展读能力。

(4) 速度与持久性

MongoDB的驱动,实现一个写入语义 fire and forget ,即通过驱动,调用写入时,可以立即得到返回得到成功的结果(即使是报错),这样让写入的速度更加快,当然会有一定的不安全性,完全依赖网络。 

MongoDB提供了Journaling日志的概念,实际上像mysql的binlog日志,当需要插入的时候会先往日志里面写入记录「write ahead log,即WAL」,再完成实际的数据操作,这样如果出现停电,进程突然中断的情况,可以保障数据不会错误,可以通过修复功能读取Journaling日志进行修复。

(5) 数据扩展

MongoDB使用分片技术对数据进行扩展,MongoDB能自动分片、自动转移分片里面的数据块,让每一个服务器里面存储的数据都是一样大小。

4、C/S服务模型

MongoDB核心服务器主要是通过mongod程序启动的「如同mysql服务端是通过mysqld程序启动的一般」而且在启动时不需对MongoDB使用的内存进行配置,因为其设计哲学是内存管理最好是交给操作系统「个人是第一次听到这种理念」,缺少内存配置是MongoDB的设计亮点,另外,还可通过mongos路由服务器使用分片功能。

MongoDB的主要客户端,是可以交互的JS Shell,通过mongo启动「对比mysql的客户端也是通过mysql程序启动」使用JS Shell能使用JS直接与MongoDB进行交流,像使用SQL语句查询MySQL数据一样使用JS语法查询MongoDB的数据,另外还提供了各种语言的驱动包,方便各种语言的接入「这是通常是必然的,任何一个服务组件都要提供相应的编程语言的SDK」。

5、完善的命令行工具

MongoDB CLI for Cloud Manager and Ops Manager | MongoDB

mongodump和mongorestore:

备份和恢复数据库的标准工具。输出BSON格式,迁移数据库。

mongoexport和mongoimport:

用来导入导出JSON、CSV和TSV数据,数据需要支持多格式时有用。

mongoimport:

还能用与大数据集的初始导入,但是在导入前顺便还要注意一下,为了能充分利用好MongoDB通常需要对数据模型做一些调整。

mongosniff:

网络嗅探工具,用来观察发送到数据库的操作。基本就是把网络上传输的BSON转换为易于人们阅读的shell语句。

因此,可以总结得到,MongoDB结合键值存储和关系数据库的最好特性。

因为简单,所以数据极快,而且相对容易伸缩还提供复杂查询机制的数据库。

MongoDB需要跑在64位的服务器上面,且最好单独部署,因为是数据库,所以也需要对其进行热备、冷备处理。

6、安装MongoDB

https://blog.csdn.net/william_n/article/details/127753800

7、工具安装使用「含客户端」

https://blog.csdn.net/william_n/article/details/127753800

8、几个shell实操

https://blog.csdn.net/william_n/article/details/127753972

9、代码实践

在Java中使用MongoDB

1、使用maven引入jar包

这里引用的是最新的驱动包,提供了一套新的访问连接方式

        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>3.8.0-beta3</version>
        </dependency>

2、创建一个访问客户端

MongoClient client = MongoClients.create(“mongodb://10.201.76.94:27017”);
 

3、获取集合数量

public long count() {
        MongoClient client = this.getClient();
        MongoCollection<Document> collections= client.getDatabase("mongodb_db_name").getCollection("mongodb_collection_name");
        return collections.count();
    }
 

4、查询集合

public List<Document> find(Document params,Bson sort,int skip,int limit) {
        MongoClient client = this.getClient();
        MongoCollection<Document> collections= client.getDatabase("mongodb_db_name").getCollection("mongodb_collection_name");
        List<Document> list = new ArrayList<Document>(Integer.valueOf(config.getPro("sync_limit")));
    collections.find(params).sort(sort).skip(skip).limit(limit).forEach(new Block<Document>() {
            @Override
            public void apply(Document document) {
                list.add(document);
            }
        });
        return list;
    }
 

这里只举例了简单的链接与简单的MongoDB操作,可见其操作的容易性。

使用驱动时是基于TCP套接字与MongoDB进行通信的,如果查询结果较多,恰好无法全部放进第一服务器中,将会向服务器发送一个getmore指令获取下一批查询结果。

插入数据到服务器时间,不会等待服务器的响应,驱动会假设写入是成功的,实际是使用客户端生成对象id,但是该行为可以通过配置配置,可以通过安全模式开启,安全模式可以校验服务器端插入的错误。

PHP中使用MongoDB

面向过程

html/app.test/public/mongodb.php · William_ning/docker-lnmp-dev-env-sh - Gitee.com

mongodb.php

<?php

// https://www.runoob.com/mongodb/php7-mongdb-tutorial.html


function write()
{

    // 连接mongodb服务器
    $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
    $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);

    // 插入数据
    $bulk = new MongoDB\Driver\BulkWrite;
    $document = ['_id' => new MongoDB\BSON\ObjectID, 'name' => '菜鸟教程'];

    // 产生文档id
    $_id = $bulk->insert($document);
    // var_dump($_id);

    $result = $manager->executeBulkWrite('test.runoob', $bulk, $writeConcern);
    var_dump($result);
}

// 读取数据
// 里我们将三个网址数据插入到 test 数据库的 sites 集合,并读取迭代出来
function read()
{
    $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");

    // 插入数据
    $bulk = new MongoDB\Driver\BulkWrite;
    $bulk->insert(['x' => 1, 'name' => '菜鸟教程', 'url' => 'http://www.runoob.com']);
    $bulk->insert(['x' => 2, 'name' => 'Google', 'url' => 'http://www.google.com']);
    $bulk->insert(['x' => 3, 'name' => 'taobao', 'url' => 'http://www.taobao.com']);
    $manager->executeBulkWrite('test.sites', $bulk);

    // 过滤条件
    $filter = ['x' => ['$gt' => 1]];
    $options = [
        'projection' => ['_id' => 0],
        'sort' => ['x' => -1],
    ];

    // 查询数据
    $query = new MongoDB\Driver\Query($filter, $options);
    $cursor = $manager->executeQuery('test.sites', $query);

    foreach ($cursor as $document) {
        print_r($document);
    }
}

// 更新数据
// 接下来我们将更新 test 数据库 sites 集合中 x 为 2 的数据:
function update()
{
    $bulk = new MongoDB\Driver\BulkWrite;
    $bulk->update(
        ['x' => 2],
        ['$set' => ['name' => '菜鸟工具', 'url' => 'tool.runoob.com']],
        ['multi' => false, 'upsert' => false]
    );

    $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
    $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
    $result = $manager->executeBulkWrite('test.sites', $bulk, $writeConcern);
    var_dump($result);
}

// 删除数据
// 以下实例删除了 x 为 1 和 x 为 2的数据,注意 limit 参数的区别:
function delete()
{
    $bulk = new MongoDB\Driver\BulkWrite;
    $bulk->delete(['x' => 1], ['limit' => 1]);   // limit 为 1 时,删除第一条匹配数据
    $bulk->delete(['x' => 2], ['limit' => 0]);   // limit 为 0 时,删除所有匹配数据

    $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
    $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
    $result = $manager->executeBulkWrite('test.sites', $bulk, $writeConcern);
    var_dump($result);
}

write();
read();
update();
delete();

OOP

html/app.test/public/MongoDB-class.php · William_ning/docker-lnmp-dev-env-sh - Gitee.com

MongoDB.php

<?php

// https://www.runoob.com/mongodb/php7-mongdb-tutorial.html

class MongoDB
{
    public $manager = null;
    public $writeConcern = null;

    public function __construct()
    {
        // 连接mongodb服务器
        if(is_null($this->manager)){
            $this->manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
        }
        if(is_null($this->writeConcern)){
            $this->writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
        }
    }

    // 插入数据
    function write()
    {
        $document = ['_id' => new MongoDB\BSON\ObjectID, 'name' => '菜鸟教程'];

        // [BulkWrite objects may only be executed once and this instance has already been executed]
        $bulk = new MongoDB\Driver\BulkWrite;
        $_id = $bulk->insert($document);

        $result = $this->manager->executeBulkWrite('test.runoob', $bulk, $this->writeConcern);
        var_dump($result);
    }

    // 读取数据
    // 里我们将三个网址数据插入到 test 数据库的 sites 集合,并读取迭代出来
    function read()
    {
        // 批量插入数据
        $bulk = new MongoDB\Driver\BulkWrite;
        $bulk->insert(['x' => 1, 'name' => '菜鸟教程', 'url' => 'http://www.runoob.com']);
        $bulk->insert(['x' => 2, 'name' => 'Google', 'url' => 'http://www.google.com']);
        $bulk->insert(['x' => 3, 'name' => 'taobao', 'url' => 'http://www.taobao.com']);
        $this->manager->executeBulkWrite('test.sites', $bulk);

        // 过滤条件
        $filter = ['x' => ['$gt' => 1]];
        $options = [
            'projection' => ['_id' => 0],
            'sort' => ['x' => -1],
        ];

        // 查询数据
        $query = new MongoDB\Driver\Query($filter, $options);
        $cursor = $this->manager->executeQuery('test.sites', $query);

        foreach ($cursor as $document) {
            print_r($document);
        }
    }

    // 更新数据
    // 接下来我们将更新 test 数据库 sites 集合中 x 为 2 的数据:
    function update()
    {
        $bulk = new MongoDB\Driver\BulkWrite;
        $bulk->update(
            ['x' => 2],
            ['$set' => ['name' => '菜鸟工具', 'url' => 'tool.runoob.com']],
            ['multi' => false, 'upsert' => false]
        );

        $result = $this->manager->executeBulkWrite('test.sites', $bulk, $this->writeConcern);
        var_dump($result);
    }

    // 删除数据
    // 以下实例删除了 x 为 1 和 x 为 2的数据,注意 limit 参数的区别:
    function delete()
    {
        $bulk = new MongoDB\Driver\BulkWrite;
        $bulk->delete(['x' => 1], ['limit' => 1]);   // limit 为 1 时,删除第一条匹配数据
        $bulk->delete(['x' => 2], ['limit' => 0]);   // limit 为 0 时,删除所有匹配数据

        $result = $this->manager->executeBulkWrite('test.sites', $bulk, $this->writeConcern);
        var_dump($result);
    }
}

$mongodb = new MongoDB();
$mongodb->write();
$mongodb->read();
$mongodb->update();
$mongodb->delete();

// 输出结果:
// ➜  html git:(master) ✗ php app.test/public/MongoDB-class.php
// object(MongoDB\Driver\WriteResult)#7 (9) {
//   ["nInserted"]=>
//   int(1)
//   ["nMatched"]=>
//   int(0)
//   ["nModified"]=>
//   int(0)
//   ["nRemoved"]=>
//   int(0)
//   ["nUpserted"]=>
//   int(0)
//   ["upsertedIds"]=>
//   array(0) {
//   }
//   ["writeErrors"]=>
//   array(0) {
//   }
//   ["writeConcernError"]=>
//   NULL
//   ["writeConcern"]=>
//   object(MongoDB\Driver\WriteConcern)#8 (2) {
//     ["w"]=>
//     string(8) "majority"
//     ["wtimeout"]=>
//     int(1000)
//   }
// }
// stdClass Object
// (
//     [x] => 3
//     [name] => taobao
//     [url] => http://www.taobao.com
// )
// stdClass Object
// (
//     [x] => 2
//     [name] => Google
//     [url] => http://www.google.com
// )
// object(MongoDB\Driver\WriteResult)#5 (9) {
//   ["nInserted"]=>
//   int(0)
//   ["nMatched"]=>
//   int(1)
//   ["nModified"]=>
//   int(1)
//   ["nRemoved"]=>
//   int(0)
//   ["nUpserted"]=>
//   int(0)
//   ["upsertedIds"]=>
//   array(0) {
//   }
//   ["writeErrors"]=>
//   array(0) {
//   }
//   ["writeConcernError"]=>
//   NULL
//   ["writeConcern"]=>
//   object(MongoDB\Driver\WriteConcern)#6 (2) {
//     ["w"]=>
//     string(8) "majority"
//     ["wtimeout"]=>
//     int(1000)
//   }
// }
// object(MongoDB\Driver\WriteResult)#9 (9) {
//   ["nInserted"]=>
//   int(0)
//   ["nMatched"]=>
//   int(0)
//   ["nModified"]=>
//   int(0)
//   ["nRemoved"]=>
//   int(2)
//   ["nUpserted"]=>
//   int(0)
//   ["upsertedIds"]=>
//   array(0) {
//   }
//   ["writeErrors"]=>
//   array(0) {
//   }
//   ["writeConcernError"]=>
//   NULL
//   ["writeConcern"]=>
//   object(MongoDB\Driver\WriteConcern)#6 (2) {
//     ["w"]=>
//     string(8) "majority"
//     ["wtimeout"]=>
//     int(1000)
//   }
// }
// ➜  html git:(master) ✗ 

3. 学习完感受

首先是安装方式,跟常见的关系型数据库,如mysql基本相同,不论cli工具还是GUI工具亦是一样

然后是软件架构方面,也是最常用的C/S架构,没有过多要说的。

语法方面确实可以看到是集合了nosql和sql的特点,上手还是挺简单。

另外是,具体实现方面,目前看来,是参考了关系型数据库的实现,这个无可厚非,技术本身从来都是相互学习,借鉴。 不过具体深层实现原理TBD。

对比其他NoSQL,学习成本差不多,具有的功能「主从副本,分片存储,导入导出,备份还原,监控,以及索引优化」,也是目前主流NoSQL普遍具备,实现方式,也是常见的方式「索引底层数据结构是B Tree, MySQL索引底层通过B+ Tree」,细节上有些区别。

基于文件系统存储,并非如同memcache,redis主要存储在内存中「文件存储作为数据可靠性保证手段」。

3.问题/补充

TBD

4.参考

参见文档阅读列表

后续补充

...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值