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主要存储在内存中「文件存储作为数据可靠性保证手段」。
|