【编程不良人】MongoDB最新实战教程学习笔记
简介
视频链接:01.简介和历史_哔哩哔哩_bilibili
文档地址: https://docs.mongodb.com/manual/
- MongoDB教程:MongoDB 教程 | 菜鸟教程
注意:整个课程大部分都来自菜鸟教程,可以直接在菜鸟教程中结果实例学习即可,有针对性薛学习。
说明
官方
MongoDB是一个
文档数据库
,旨在方便应用开发和扩展。百度百科
MongoDB是一个基于分布式文件存储的数据库
(支持集群、分片处理)。由C++语言编写。旨在为WEB应用提供可扩展高性能的数据存储解决方案
。
MongoDB是一个介于关系数据库和非关系数据库
之间的产品(偏向于非关系型数据库NoSQL),是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式(对json进行扩展),因此可以存储比较复杂的数据类型。MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引
。
总结: mongoDB是一个非关系型文档数据库。
历史
2009年2月,MongoDB数据库首次在数据库领域亮相,打破了关系型数据库一统天下的局面;
2010年8月, MongoDB 1.6发布。这个版本最大的一个功能就是Sharding---自动分片;
2014年12月, MongoDB 3.0发布。由于收购了WiredTiger 存储引擎,大幅提升了MongoDB的写入性能;
2015年12月,3.2版本发布,开始支持了关系型数据库的核心功能:关联。你可以一次同时查询多个MongoDB的集合。
2016年, MongoDB推出Atlas,在AWS、 Azure 和GCP上的MongoDB托管服务;
2017年10月,MongoDB成功在纳斯达克敲钟,成为26年来第一家以数据库产品为主要业务的上市公司。
2018年6月, MongoDB4.0 发布推出ACID事务支持,成为第一个支持强事务的NoSQL数据库;
2018年--至今,MongoDB已经从一个在数据库领域籍籍无名的“小透明”,变成了话题度和热度都很高的“流量”数据库。
特点
视频链接:02.特点&应用场景_哔哩哔哩_bilibili
特点
面向集合存储,易存储对象类型的数据
支持查询以及动态查询
支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言
文件存储格式为BSON(一种JSON的扩展)
支持复制和故障恢复和分片
支持事务支持(要求性不高,不能完全取代关系型数据库)
索引、聚合、关联....
应用场景
游戏应用:使用云数据库MongoDB作为游戏服务器的数据库存储用户信息。用户的游戏装备、积分等直接以内嵌文档的形式存储,方便进行查询与更新。
物流应用:使用云数据库MongoDB存储订单信息,订单状态在运送过程中会不断更新,以云数据库MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来,方便快捷且一目了然。
社交应用:使用云数据库MongoDB存储用户信息以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。并且,云数据库MongoDB非常适合用来存储聊天记录,因为它提供了非常丰富的查询,并在写入和读取方面都相对较快。
视频直播:使用云数据库MongoDB存储用户信息、礼物信息等。
大数据应用:使用云数据库MongoDB作为大数据的云存储系统,随时进行数据提取分析,掌握行业动态。
安装
视频链接:03.传统方式安装_哔哩哔哩_bilibili
传统方式
# 1.下载 MongoDB- https://www.mongodb.com/try/download/community
# 2.将下载安装包上传到 linux 系统- tar -zxf mongodb-linux-aarch64-ubuntu2004-5.0.5.tgz
# 3.查看安装目录- ls`bin`目录 用来存放启动mongoDB的服务以及客户端链接的脚本文件等
# 4.启动 MongoDB 服务- ./mongod --port=27017 --dbpath=../data --logpath=../logs/mongo.log`--port` 指定服务监听端口号 默认为 27017`--dbpath` 指定 mongodb 数据存放目录 启动要求目录必须存在`--logpath` 指定 mongodb 日志文件存放位置
注意: 由于指定日志文件因此启动时日志输出到日志中终端不显示任何日志
# 5.客户端连接- ./mongo --port=27017
Docker方式
视频链接:04.Docker 方式安装_哔哩哔哩_bilibili
# 1.拉取 mongodb 镜像- docker pull mongo:5.0.5
# 2.运行 mongo 镜像- docker run -d --name mongo --p 27017:27017 mongo:5.0.5
# 3.进入 mongo 容器- docker exec -it bc6c bash
Windows安装方式
msi方式安装+Navicat连接MongoDB
MongoDB安装包下载地址:Download MongoDB Community Server | MongoDB
插件安装包地址:MongoDB Shell Download | MongoDB
配套安装视频:新手软件安装教程【5】MongoDB6安装教程_哔哩哔哩_bilibili
解决Navicat连接Mongodb不显示数据库_mogodb admin 数据库不出现_每天进前进一小步的博客-CSDN博客
核心概念
视频链接:05.核心概念(库、集合、文档)_哔哩哔哩_bilibili
库<DataBase>
mongodb中的库就类似于传统关系型数据库中库的概念,用来通过不同库隔离不同应用数据
。
mongodb中可以建立多个数据库。每一个库都有自己的集合和权限,不同的数据库也放置在不同的文件中。默认的数据库为"test",数据库存储在启动指定的data目录中。
集合<Collection>
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表的概念
。
集合存在于数据库中,一个库中可以创建多个集合。每个集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
文档<Document>
文档集合中一条条记录,是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
一个简单的文档例子如下:
{"site":"www.baizhiedu.xin", "name":"编程不良人"}
关系总结
RDBMS | MongoDB |
---|---|
数据库<database> | 数据库<database> |
表<table> | 集合<collection> |
行<row> | 文档<document> |
列<colume> | 字段<field> |
基本操作
视频链接:06.库的相关操作_哔哩哔哩_bilibili
库<database>
查看所有库
> show databases; | show dbs;
注意:
admin
: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。local
: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合。config
: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
创建数据库
> use 库名
注意: use 代表创建并使用,当库中没有数据时默认不显示这个库
。删除数据库
默认删除当前选中的库
> db.dropDatabase() ---注意此处有括号
查看当前所在库
> db;
集合<Collection>
视频链接:07.集合的相关操作_哔哩哔哩_bilibili
查看库中所有集合
> show collections; | show tables;
创建集合
> db.createCollection('集合名称', [options])
options可以是如下参数:
字段 类型 描述 capped 布尔 (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。 size 数值 (可选)为固定集合指定一个最大值,即字节数。 如果 capped 为 true,也需要指定该字段。 max 数值 (可选)指定固定集合中包含文档的最大数量。
注意:当集合不存在时,向集合中插入文档也会自动创建该集合。
删除集合
> db.集合名称.drop();-- 如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
文档<document>
视频链接:08.文档的添加、查询_哔哩哔哩_bilibili
参考文档: mongosh Methods — MongoDB Manual
插入文档
单条文档
> db.集合名称.insert(document)-- 举例:> db.users.insert({"name":"编程不良人","age":23,"bir":"2012-12-12"});-- db.集合名称.insertOne():向指定集合中插入一条文档数据【推荐使用】> db.users.insertOne({"name":"编程不良人","age":23,"bir":"2012-12-12"});
多条文档
-- db.collection.insertMany():向指定集合中插入多条文档数据【推荐使用】> db.集合名称.insertMany([ <document 1> , <document 2>, ... ],{writeConcern: 1,//写入策略,默认为1,即要求确认写操作,0是不要求。ordered: true //指定是否按顺序写入,默认true,按顺序写入。})-- 举例:> db.users.insert([{"name":"不良人","age":23,"bir":"2012-12-12"},{"name":"小黑","age":25,"bir":"2012-12-12"}]);或> db.users.insertMany([{"name":"不良人","age":23,"bir":"2012-12-12"},{"name":"小黑","age":25,"bir":"2012-12-12"}]);
脚本方式
for(let i=0;i<100;i++){db.users.insert({"_id":i,"name":"编程不良人_"+i,"age":23});}-- 1、先创建数组-- 2、将数据放在数组中-- 3、一次 insert 到集合中var arr = [];for(var i=1 ; i<=20000 ; i++){arr.push({num:i});}db.numbers.insert(arr);
注意:在mongodb中每个文档都会有一个_id作为唯一标识,_id默认会自动生成,如果手动指定将使用手动指定的值作为_id 的值。
查询所有
> db.集合名称.find();
视频链接:09.文档的删除_哔哩哔哩_bilibili
删除文档
db.集合名称.remove(<query>,{justOne: <boolean>,writeConcern: <document>})-- 由于remove()方法已经过时了,现在官方推荐使用deleteOne()和deleteMany()方法。-- db.集合名称.deleteMany({query}) -- 不指定条件时删除集合下全部文档> db.users.deleteMany({});> db.users.deleteMany({age:23});-- db.集合名称.deleteOne({query}) -- 删除一条文档> db.users.deleteOne({_id:ObjectId("64108c960d0d9fdb638f66d0")});
参数说明:
query :
可选
删除的文档的条件。justOne :
可选
如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。writeConcern :
可选
抛出异常的级别。
注意:文档内容全部删除后,文档仍存在,即删除内容,不删除结构。
视频链接:10.文档的更新_哔哩哔哩_bilibili
MongoDB 更新文档 | 菜鸟教程
更新文档
db.集合名称.update(<query>,<update>,{upsert: <boolean>,multi: <boolean>,writeConcern: <document>});
参数说明:
query : update的查询条件,类似sql update查询内where后面的。
update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
upsert :
可选
,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。multi :
可选
,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。writeConcern :
可选
,抛出异常的级别。WriteConcern.NONE:没有异常抛出
WriteConcern.NORMAL:仅抛出网络错误异常,没有服务器错误异常
WriteConcern.SAFE:抛出网络错误异常、服务器错误异常;并等待服务器完成写操作。
WriteConcern.MAJORITY: 抛出网络错误异常、服务器错误异常;并等待一个主服务器完成写操作。
WriteConcern.FSYNC_SAFE: 抛出网络错误异常、服务器错误异常;写操作等待服务器将数据刷新到磁盘。
WriteConcern.JOURNAL_SAFE:抛出网络错误异常、服务器错误异常;写操作等待服务器提交到磁盘的日志文件。
WriteConcern.REPLICAS_SAFE:抛出网络错误异常、服务器错误异常;等待至少2台服务器完成写操作。
- db.集合名称.update({"name":"zhangsan"},{name:"11",bir:new date()}) `这个更新是将符合条件的全部更新成后面的文档,相当于先删除在更新`- db.集合名称.update({"name":"xiaohei"},{$set:{name:"mingming"}})`保留原来数据更新,但是只更新符合条件的第一条数据`- db.集合名称.update({name:”小黑”},{$set:{name:”小明”}},{multi:true}) `保留原来数据更新,更新符合条件的所有数据`- db.集合名称.update({name:”小黑”},{$set:{name:”小明”}},{multi:true,upsert:true})`保留原来数据更新,更新符合条件的所有数据,没有条件符合时插入数据
在3.2版本开始,MongoDB提供以下更新集合文档的方法:
db.collection.updateOne():向指定集合更新单个文档
db.users.updateOne({"_id":0},{$set:{"name":"小呆呆"}})
db.users.updateOne({"_id":10},{$set:{"name":"熊大"}},{upsert:true});
db.collection.updateMany():向指定集合更新多个文档
db.users.updateMany({"name":"小崔加油"},{$set:{"name":"欧力给"}});
文档查询
视频链接:11.文档的查询(一)_哔哩哔哩_bilibili
MongoDB 查询文档 | 菜鸟教程
MongoDB 查询文档使用 find() 方法。find() 方法以非结构化的方式来显示所有文档。
语法
> db.集合名称.find(query, projection)
query :可选,使用查询操作符指定查询条件
projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
> db.集合名称.find().pretty()
注意: pretty()方法以格式化的方式来显示所有文档。
对比语法
如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 |
{<key>:<value> }
|
db.col.find({"by":"菜鸟教程"}).pretty()
|
where by = '菜鸟教程'
|
小于 |
{<key>:{$lt:<value>}}
|
db.col.find({"likes":{$lt:50}}).pretty()
|
where likes < 50
|
小于或等于 |
{<key>:{$lte:<value>}}
|
db.col.find({"likes":{$lte:50}}).pretty()
|
where likes <= 50
|
大于 |
{<key>:{$gt:<value>}}
|
db.col.find({"likes":{$gt:50}}).pretty()
|
where likes > 50
|
大于或等于 |
{<key>:{$gte:<value>}}
|
db.col.find({"likes":{$gte:50}}).pretty()
|
where likes >= 50
|
不等于 |
{<key>:{$ne:<value>}}
|
db.col.find({"likes":{$ne:50}}).pretty()
|
where likes != 50
|
db.users.find({"age":{$gte:15}})
AND
> db.集合名称.find({key1:value1, key2:value2,...}).pretty()
类似于 WHERE 语句:WHERE key1=value1 AND key2=value2
db.users.find({"age":27,"name":"欧力给",_id:8});
db.users.find({"age":3,"age":27});同一字段多次出现查询条件时,只有最后的查询条件才生效,即后面会覆盖前面的查询条件
OR
MongoDB OR 条件语句使用了关键字 $or,语法格式如下:
> db.集合名称.find({$or: [{key1: value1}, {key2:value2}]}).pretty()
类似于 WHERE 语句:WHERE key1=value1 or key2=value2
db.users.find({$or:[{_id:3},{age:15}]});
视频链接:12.文档的查询(二)_哔哩哔哩_bilibili
AND 和 OR 联合
类似SQL语句为:'where age >50 AND (name = '编程不良人' OR name = 'MongoDB')'
> db.集合名称.find({"age": {$gt:50}, $or: [{"name": "编程不良人"},{"name": "MongoDB"}]}).pretty();
db.users.find({age:{$gt:15},$or:[{_id:3},{age:15}]});
数组中查询
-- 测试数据> db.集合名称.insert({ "_id" : 11, "age" : 29, "likes" : [ "看电视", "读书xx", "美女" ], "name" : "不良人_xx_11" })-- 执行数组查询> db.users.find({likes:"看电视"})-- $size 按照数组长度查询> db.users.find({likes:{$size:3}});
模糊查询
类似 SQL 中为 'where name like '%name%''
> db.users.find({likes:/良/});
注意:在 mongoDB 中使用正则表达式可以是实现近似模糊查询功能
排序
视频链接:13.文档的查询(三)_哔哩哔哩_bilibili
> db.集合名称.find().sort({name:1,age:1}),- 1 升序 -1 降序
类似 SQL 语句为: 'order by name,age'
分页
> db.集合名称.find().sort({条件}).skip(start).limit(rows);
类似于 SQL 语句为: 'limit start,rows'
总条数
> db.集合名称.count();> db.集合名称.find({"name":"编程不良人"}).count();
类似于 SQL 语句为: 'select count(id) from ....'
DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.
db.users.countDocuments();
db.users.estimatedDocumentCount();
去重
> db.集合名称.distinct('字段')
类似于 SQL 语句为: 'select distinct name from ....'
db.users.distinct("age");
指定返回字段
> db.集合名称.find({条件},{name:1,age:1}) - 参数2: 1 返回 0 不返回
db.users.find({},{"name":1});查询所有,返回指定字段
db.users.find({age:{$lt:17}},{name:1});按照指定条件查询,返回指定字段
db.users.find({age:{$lt:17}},{_id:0,name:1});按照指定条件查询,返回指定字段,不返回id,注意id是唯一索引
$type
视频链接:14.$type操作符_哔哩哔哩_bilibili
说明
$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。
MongoDB 中可以使用的类型如下表所示:
类型 | 数字 | 备注 |
---|---|---|
Double | 1 | |
String | 2 | |
Object | 3 | |
Array | 4 | |
Binary data | 5 | |
Undefined | 6 | 已废弃。 |
Object id | 7 | |
Boolean | 8 | |
Date | 9 | |
Null | 10 | |
Regular Expression | 11 | |
JavaScript | 13 | |
Symbol | 14 | |
JavaScript (with scope) | 15 | |
32-bit integer | 16 | |
Timestamp | 17 | |
64-bit integer | 18 | |
Min key | 255 |
Query with -1 .
|
Max key | 127 |
使用
> db.col.insert({title: 'PHP 教程', description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',by: '编程不良人',url: 'http://www.baizhiedu.xin',tags: ['php'],likes: 200});> db.col.insert({title: 'Java 教程', description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',by: '编程不良人',url: 'http://www.baizhiedu.xin',tags: ['java'],likes: 550});> db.col.insert({title: 'MongoDB 教程', description: 'MongoDB 是一个 Nosql 数据库',by: '编程不良人',url: 'http://www.baizhiedu.xin',tags: ['mongodb'],likes: 100});> db.col.insert({title: 2233, description: '2233 是一个 B站的',by: '编程不良人',url: 'http://www.baizhiedu.xin',tags: ['2233'],likes: 100});
如果想获取 "col" 集合中 title 为 String 的数据,你可以使用以下命令:
db.col.find({"title" : {$type : 2}}).pretty();或db.col.find({"title" : {$type : 'string'}}).pretty();
如果想获取 "col" 集合中 tags 为 Array 的数据,你可以使用以下命令:
db.col.find({"tags":{$type : 4}}).pretty();或db.col.find({"tags" : {$type : 'array'}}).pretty();
索引<index>
视频链接:15.索引简介&原理(一)_哔哩哔哩_bilibili
Indexes — MongoDB Manual
MongoDB 索引 | 菜鸟教程
说明
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
原理
从根本上说,MongoDB中的索引与其他数据库系统中的索引类似。MongoDB在集合层面上定义了索引,并支持对MongoDB集合中的任何字段或文档的子字段进行索引。
默认_id已经创建了索引。
操作
视频链接:16.索引的基本操作(二)_哔哩哔哩_bilibili
0、创建索引
> db.集合名称.createIndex(keys, options)> db.集合名称.createIndex({"title":1,"description":-1})
说明: 语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
createIndex() 接收可选参数,可选参数列表如下:
Parameter | Type | Description |
---|---|---|
background
|
Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 |
unique
|
Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name
|
string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds
|
integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v
|
index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. |
1、查看集合索引
> db.集合名称.getIndexes()
2、查看集合索引大小
> db.集合名称.totalIndexSize()
3、删除集合所有索引(不包含_id索引)
> db.集合名称.dropIndexes()
4、删除集合指定索引
> db.集合名称.dropIndex("索引名称")
复合索引
视频链接:17.索引之复合索引(三)_哔哩哔哩_bilibili
说明: 一个索引的值是由多个 key 进行维护的索引的称之为复合索引
> db.集合名称.createIndex({"title":1,"description":-1})
注意: mongoDB 中复合索引和传统关系型数据库一致都是左前缀匹配原则
聚合<aggregate>
视频链接:18.聚合查询_哔哩哔哩_bilibili
说明
MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似 SQL 语句中的 count(*)。
使用
db.test.insertMany([{title: 'MongoDB Overview', description: 'MongoDB is no sql database',by_user: 'runoob.com',url: 'http://www.runoob.com',tags: ['mongodb', 'database', 'NoSQL'],likes: 100},{title: 'NoSQL Overview', description: 'No sql database is very fast',by_user: 'runoob.com',url: 'http://www.runoob.com',tags: ['mongodb', 'database', 'NoSQL'],likes: 10},{title: 'Neo4j Overview', description: 'Neo4j is no sql database',by_user: 'Neo4j',url: 'http://www.neo4j.com',tags: ['neo4j', 'database', 'NoSQL'],likes: 750}]);
现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:
> db.test.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
注意:此处的_id是分组表示,不是文档的 _id.
常见聚合表达式
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 将值加入一个数组中,不会判断是否有重复的值。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
整合应用
视频链接:19.Navicat 连接 MongoDB_哔哩哔哩_bilibili
主要讲解Navicat如何连接MongoDB
附:navicat连接mongoDB不显示数据库,navicat连接mongoDB进行数据管理操作_天天喝可乐的博客-CSDN博客
视频链接:20.整合SpringBoot之环境搭建&集合操作(一)_哔哩哔哩_bilibili
说明: 这里主要以 springboot 应用为基础应用进行整合开发。
Spring Data : Spring 数据框架 JPA 、Redis、Elasticsearch、AMQP、MongoDB
JdbcTemplate
RedisTemplate
ElasticTempalte
AmqpTemplate
MongoTemplate
SpringBoot Spring Data MongoDB
环境搭建
# 引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency>
# 编写配置
# mongodb 没有开启任何安全协议# mongodb(协议)://121.5.167.13(主机):27017(端口)/baizhi(库名)spring.data.mongodb.uri=mongodb://121.5.167.13:27017/baizhi# mongodb 存在密码#spring.data.mongodb.host=tx.chenyn.cn#spring.data.mongodb.port=27017#spring.data.mongodb.database=baizhi#spring.data.mongodb.username=root#spring.data.mongodb.password=root
集合操作
创建集合
@Testpublic void testCreateCollection(){mongoTemplate.createCollection("users");//参数: 创建集合名称}
注意: 创建的集合已经存在时,再次创建会报错,因此创建前需要判断集合时候已经存在
/*** 创建集合*/@Testpublic void testCreateCollection(){// 判断集合是否存在boolean isExist = mongoTemplate.collectionExists("products");// 不存在时创建集合if (!isExist) {mongoTemplate.createCollection("products");}}
删除集合
/*** 删除集合*/@Testpublic void testDropCollection(){mongoTemplate.dropCollection("products");}
相关注解
视频链接:21.整合SpringBoot之文档的添加(二)_哔哩哔哩_bilibili
Java-->对象-->JSON-->MongoDB
类---文档
@Document
对应 类修饰范围: 用在类上
作用: 用来映射这个类的一个对象为 mongo 中一条文档数据
属性:(
value 、collection
)用来指定操作的集合名称
@Id
对应 要指定为_id的变量名修饰范围: 用在成员变量、方法上,只能出现一次
作用: 用来将成员变量的值映射为文档的_id 的值
@Field
对应 剩余变量名(变量名都按照类中属性名定义时,可以不指定,即同名时可不指定)修饰范围: 用在成员变量、方法上
作用: 用来将成员变量以及值映射为文档中一个key、value对
属性: (
name,value
)用来指定在文档中 key 的名称,默认为成员变量名
@Transient
不参与文档转换修饰范围: 用在成员变量、方法上
作用 : 用来指定改成员变量,不参与文档的序列化
文档操作
视频链接:22.整合SpringBoot之文档的查询(三)_哔哩哔哩_bilibili
视频链接:23.整合SpringBoot之文档的查询(四)_哔哩哔哩_bilibili
查询
Criteria
常见查询
@Testpublic void testQuery(){//基于 id 查询template.findById("1",User.class);//查询所有template.findAll(User.class);template.find(new Query(),User.class);//等值查询template.find(Query.query(Criteria.where("name").is("编程不良人")), User.class);// > gt < lt >= gte <= ltetemplate.find(Query.query(Criteria.where("age").lt(25)),User.class);template.find(Query.query(Criteria.where("age").gt(25)),User.class);template.find(Query.query(Criteria.where("age").lte(25)),User.class);template.find(Query.query(Criteria.where("age").gte(25)),User.class);//andtemplate.find(Query.query(Criteria.where("name").is("编程不良人").and("age").is(23)),User.class);//orCriteria criteria = new Criteria().orOperator(Criteria.where("name").is("编程不良人_1"),Criteria.where("name").is("编程不良人_2"));template.find(Query.query(criteria), User.class);//and orCriteria criteria1 = new Criteria().and("age").is(23).orOperator(Criteria.where("name").is("编程不良人_1"),Criteria.where("name").is("编程不良人_2"));template.find(Query.query(criteria1), User.class);//sort 排序Query query = new Query();query.with(Sort.by(Sort.Order.desc("age")));//desc 降序 asc 升序template.find(query, User.class);//skip limit 分页Query queryPage = new Query();queryPage.with(Sort.by(Sort.Order.desc("age")))//desc 降序 asc 升序.skip(0) //起始条数.limit(4); //每页显示记录数template.find(queryPage, User.class);//count 总条数template.count(new Query(), User.class);//distinct 去重//参数 1:查询条件 参数 2: 去重字段 参数 3: 操作集合 参数 4: 返回类型template.findDistinct(new Query(), "name", User.class, String.class);//使用 json 字符串方式查询 Query query = new BasicQuery("{$or:[{name:'编程不良人'},{name:'徐凤年'}]}", "{name:0}");template.find(query, User.class);}
添加
@Testpublic void testSaveOrUpdate(){User user = new User();user.setId("1");user.setAge(23);user.setName("编程不良人_1");user.setBir(new Date());User userDB = mongoTemplate.insert(user);//返回保存的对象 insert or saveSystem.out.println(userDB);}
插入重复数据时:
insert
报DuplicateKeyException
提示主键重复;save
对已存在的数据进行更新。
批处理操作时:
insert
可以一次性插入整个数据,效率较高;save
需遍历整个数据,一次插入或更新,效率较低。
更新:24.整合SpringBoot之文档的更新&删除(五)_哔哩哔哩_bilibili
@Testpublic void testUpdate(){//1.更新条件Query query = Query.query(Criteria.where("age").is(23));//2.更新内容Update update = new Update();update.set("name","编程小陈陈");//单条更新mongoTemplate.updateFirst(query, update, User.class);//多条更新mongoTemplate.updateMulti(query, update, User.class);//更新插入mongoTemplate.upsert(query,update,User.class);//返回值均为 updateResult//System.out.println("匹配条数:" + updateResult.getMatchedCount());//System.out.println("修改条数:" + updateResult.getModifiedCount());//System.out.println("插入id_:" + updateResult.getUpsertedId());}
删除
@Testpublic void testDelete(){//删除所有mongoTemplate.remove(new Query(),User.class);//条件删除mongoTemplate.remove(Query.query(Criteria.where("name").is("编程不良人")),User.class);}
项目实操
pom.xml依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--spring-boot-starter-data-mongodb--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
application.properties配置
# 建立连接spring.data.mongodb.uri=mongodb://127.0.0.1:27017/cjn
实体类User
package com.study.entity;import lombok.*;import lombok.experimental.Accessors;import org.springframework.data.annotation.Id;import org.springframework.data.mongodb.core.mapping.Document;import org.springframework.data.mongodb.core.mapping.Field;import java.util.Date;/*** @ClassName User* @Description TODO* @Author Jiangnan Cui* @Date 2023/3/18 22:21* @Version 1.0*/@Data@Accessors(chain = true)@Document(value = "users")public class User {@Idprivate Integer id;@Field(value = "username")private String name;@Fieldprivate Double salary;@Fieldprivate Date birthday;}
测试类
package com.study.test;import com.mongodb.client.result.DeleteResult;import com.mongodb.client.result.UpdateResult;import com.study.entity.User;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.data.domain.Sort;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.core.query.BasicQuery;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 java.util.ArrayList;import java.util.Date;import java.util.List;/*** @ClassName MongodbTest* @Description TODO* @Author Jiangnan Cui* @Date 2023/3/18 21:34* @Version 1.0*/@SpringBootTestpublic class MongodbTest {@Autowiredprivate MongoTemplate mongoTemplate;/*** 创建集合*/@Testpublic void testCreateCollection() {// 判断集合是否存在boolean isExist = mongoTemplate.collectionExists("products");// 不存在时创建集合if (!isExist) {mongoTemplate.createCollection("products");}}/*** 删除集合*/@Testpublic void testDropCollection() {mongoTemplate.dropCollection("products");}/*** 添加单个文档1*/@Testpublic void testSaveDocument() {User user = new User();user.setId(1).setName("熊大").setSalary(800.0).setBirthday(new Date());mongoTemplate.save(user);}/*** 添加单个文档2*/@Testpublic void testAddDocument() {User user = new User();user.setId(2).setName("熊二").setSalary(500.0).setBirthday(new Date());mongoTemplate.insert(user);}/*** 批量添加文档*/@Testpublic void testBatchInsertDocument() {List<User> userList = new ArrayList<>();userList.add(new User().setId(6).setName("猪猪侠").setSalary(1000.0).setBirthday(new Date()));userList.add(new User().setId(7).setName("小呆呆").setSalary(600.0).setBirthday(new Date()));userList.add(new User().setId(8).setName("波比").setSalary(50.0).setBirthday(new Date()));// mongoTemplate.insert(userList, User.class);// 上下两种方式均可,上面指定类名,下面指定集合名mongoTemplate.insert(userList, "users");}/*** 查询操作*/@Testpublic void testFind() {// 1.查询所有List<User> users = mongoTemplate.findAll(User.class, "users");users.forEach(System.out::println);System.out.println();// 或List<User> userList = mongoTemplate.findAll(User.class);userList.forEach(System.out::println);System.out.println();// 2.基于id查一个User user = mongoTemplate.findById(1, User.class, "users");System.out.println(user);System.out.println();// 或User user2 = mongoTemplate.findById(1, User.class);System.out.println(user2);System.out.println();// 3.条件查询// 3.1 查询所有List<User> users2 = mongoTemplate.find(new Query(), User.class, "users");users2.forEach(System.out::println);System.out.println();// 或List<User> usersList2 = mongoTemplate.find(new Query(), User.class);usersList2.forEach(System.out::println);System.out.println();// 3.2 等值查询:注意值要写对类型,例如不要将Integer写成StringList<User> users3 = mongoTemplate.find(new Query(Criteria.where("salary").is(600)), User.class);users3.forEach(System.out::println);System.out.println();// 3.3 不等值查询List<User> users1 = mongoTemplate.find(new Query().addCriteria(Criteria.where("salary").gt(800)), User.class);users1.forEach(System.out::println);System.out.println();// 3.4 and查询List<User> users4 = mongoTemplate.find(new Query().addCriteria(Criteria.where("salary").gt(800).and("name").is("光头强")), User.class);users4.forEach(System.out::println);System.out.println();// 3.5 or查询List<User> users5 = mongoTemplate.find(new Query().addCriteria(new Criteria().orOperator(Criteria.where("salary").gt(800),Criteria.where("name").is("小呆呆"))),User.class);users5.forEach(System.out::println);System.out.println();// 3.6 and、or查询连用List<User> users6 = mongoTemplate.find(new Query().addCriteria(new Criteria().orOperator(Criteria.where("name").in("光头强", "小呆呆"))).addCriteria(Criteria.where("salary").is(600)), User.class);users6.forEach(System.out::println);System.out.println();// 4.排序List<User> users7 = mongoTemplate.find(new Query().with(Sort.by(Sort.Order.desc("salary"))), User.class);users7.forEach(System.out::println);System.out.println();// 5.排序后分页List<User> users8 = mongoTemplate.find(new Query().with(Sort.by(Sort.Order.asc("salary"))).skip(0).limit(2), User.class);users8.forEach(System.out::println);System.out.println();// 6.查询总条数long count = mongoTemplate.count(new Query(), User.class);System.out.println("count = " + count);System.out.println();// 7.去重List<Double> salaryList = mongoTemplate.findDistinct(new Query(), "salary", User.class, Double.class);salaryList.forEach(System.out::println);System.out.println();// 8.使用json字符串方式查询Query query = new BasicQuery("{$or: [{name:'小呆呆'},{name:'光头强'}]}", "{birthday:0}");List<User> users9 = mongoTemplate.find(query, User.class);users9.forEach(System.out::println);}/*** 更新文档*/@Testpublic void testUpdateDocument() {Update update = new Update();update.set("salary", 2500);// 更新一条mongoTemplate.updateFirst(Query.query(Criteria.where("salary").is(1000)),update,User.class);update.set("salary", 1500);// 更新多条mongoTemplate.updateMulti(Query.query(Criteria.where("salary").lt(200)),update,User.class);// 插入更新update.setOnInsert("id", 10);update.set("name", "我是之前没有的");// 更新多条UpdateResult updateResult = mongoTemplate.upsert(Query.query(Criteria.where("salary").gt(30000)),update,User.class);System.out.println("updateResult.getMatchedCount() = " + updateResult.getMatchedCount());System.out.println("updateResult.getModifiedCount() = " + updateResult.getModifiedCount());System.out.println("updateResult.getUpsertedId() = " + updateResult.getUpsertedId());}/*** 文档删除*/@Testpublic void testRemoveDocument() {DeleteResult deleteResult = mongoTemplate.remove(Query.query(Criteria.where("id").is(9)), User.class);System.out.println("deleteResult.getDeletedCount() = " + deleteResult.getDeletedCount());}}
副本集<Replica Set>
视频链接:25.副本集简介(一)_哔哩哔哩_bilibili
说明
Replication — MongoDB Manual
MongoDB 副本集(Replica Set)是有自动故障恢复功能的主从集群,有一个Primary节点和一个或多个Secondary节点组成。副本集没有固定的主节点
,当主节点
发生故障时整个集群会选举一个主节点
为系统提供服务以保证系统的高可用。注意:这种方式并不能解决主节点的单点访问压力问题。
Automatic Failover
自动故障转移机制: 当主节点未与集合的其他成员通信超过配置的选举超时时间(默认为 10 秒)时,合格的辅助节点将调用选举以将自己提名为新的主节点。集群尝试完成新主节点的选举并恢复正常操作。
搭建副本集
视频链接:26.副本集搭建(二)_哔哩哔哩_bilibili
创建数据目录
# 在安装目录中创建- mkdir -p ../repl/data1- mkdir -p ../repl/data2- mkdir -p ../repl/data3
搭建副本集:单独操作 当前机器的ip地址
$ mongod --port 27017 --dbpath ../repl/data1 --bind_ip 0.0.0.0 --replSet myreplace/[121.5.167.13:27018,121.5.167.13:27019]$ mongod --port 27018 --dbpath ../repl/data2 --bind_ip 0.0.0.0 --replSet myreplace/[121.5.167.13:27019,121.5.167.13:27017]$ mongod --port 27019 --dbpath ../repl/data3 --bind_ip 0.0.0.0 --replSet myreplace/[121.5.167.13:27017,121.5.167.13:27018]
注意: --replSet 副本集 myreplace 副本集名称/集群中其他节点的主机和端口
配置副本集,连接任意节点
use admin
初始化副本集
> var config = { _id:"myreplace", members:[{_id:0,host:"121.5.167.13:27017"},{_id:1,host:"121.5.167.13:27018"},{_id:2,host:"121.5.167.13:27019"}]}> rs.initiate(config);//初始化配置
设置客户端临时可以访问
> rs.slaveOk(); 旧的> rs.secondaryOk(); 新的
注意:当MongoDB副本集架构只剩一个节点时,整个节点是不可用的。单主不可写。
视频链接:27.客户端操作副本集以及 Bug 说明_哔哩哔哩_bilibili
MongoDB与Navicat(直连主节点就行,连接多个节点时会提示超时)、IDEA连接(修改配置)
可参考:Mongodb学习笔记(编程不良人,基于5.0.5)_编程不良人mongodb笔记_chihiro_db的博客-CSDN博客
分片集群<Sharding Cluster>
视频链接:28.分片集群(一)_哔哩哔哩_bilibili
说明
官网:Sharding — MongoDB Manual
分片(sharding)
是指将数据拆分,将其分散存在不同机器的过程
,有时也用分区(partitioning)
来表示这个概念,将数据分散在不同的机器上,不需要功能强大的大型计算机就能存储更多的数据,处理更大的负载。
分片目的是通过分片能够增加更多机器来应对不断的增加负载和数据,还不影响应用运行。
MongoDB支持自动分片
,可以摆脱手动分片的管理困扰,集群自动切分数据做负载均衡。
MongoDB分片的基本思想就是将集合拆分成多个块,这些快分散在若干个片里,每个片只负责总数据的一部分,应用程序不必知道哪些片对应哪些数据,甚至不需要知道数据拆分了,所以在分片之前会运行一个路由进程,mongos进程,这个路由器知道所有的数据存放位置,应用只需要直接与mongos交互即可。mongos自动将请求转到相应的片上获取数据,从应用角度看分不分片没有什么区别。
架构
Shard: 用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
Config Server:mongod实例,存储了整个 ClusterMetadata。
Query Routers: 前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。
Shard Key: 片键,设置分片时需要在集合中选一个键,用该键的值作为拆分数据的依据,这个片键称之为(shard key),片键的选取很重要,片键的选取决定了数据散列是否均匀。
搭建
视频链接:29.分片搭建(二)_哔哩哔哩_bilibili
视频链接:30.集群搭建(三)_哔哩哔哩_bilibili
# 1.集群规划- Shard Server 1:27017- Shard Repl 1:27018- Shard Server 2:27019- Shard Repl 2:27020- Shard Server 3:27021- Shard Repl 3:27022- Config Server :27023- Config Server :27024- Config Server :27025- Route Process :27026# 2.进入安装的 bin 目录创建数据目录- mkdir -p ../cluster/shard/s0- mkdir -p ../cluster/shard/s0-repl- mkdir -p ../cluster/shard/s1- mkdir -p ../cluster/shard/s1-repl- mkdir -p ../cluster/shard/s2- mkdir -p ../cluster/shard/s2-repl- mkdir -p ../cluster/shard/config1- mkdir -p ../cluster/shard/config2- mkdir -p ../cluster/shard/config3# 3.启动4个 shard服务# 启动 s0、r0> ./mongod --port 27017 --dbpath ../cluster/shard/s0 --bind_ip 0.0.0.0 --shardsvr --replSet r0/121.5.167.13:27018> ./mongod --port 27018 --dbpath ../cluster/shard/s0-repl --bind_ip 0.0.0.0 --shardsvr --replSet r0/121.5.167.13:27017-- 1.登录任意节点-- 2. use admin-- 3. 执行config = { _id:"r0", members:[{_id:0,host:"121.5.167.13:27017"},{_id:1,host:"121.5.167.13:27018"},]}rs.initiate(config);//初始化# 启动 s1、r1> ./mongod --port 27019 --dbpath ../cluster/shard/s1 --bind_ip 0.0.0.0 --shardsvr --replSet r1/121.5.167.13:27020> ./mongod --port 27020 --dbpath ../cluster/shard/s1-repl --bind_ip 0.0.0.0 --shardsvr --replSet r1/121.5.167.13:27019-- 1.登录任意节点-- 2. use admin-- 3. 执行config = { _id:"r1", members:[{_id:0,host:"121.5.167.13:27019"},{_id:1,host:"121.5.167.13:27020"},]}rs.initiate(config);//初始化# 启动 s2、r2> ./mongod --port 27021 --dbpath ../cluster/shard/s2 --bind_ip 0.0.0.0 --shardsvr --replSet r2/121.5.167.13:27022> ./mongod --port 27022 --dbpath ../cluster/shard/s2-repl --bind_ip 0.0.0.0 --shardsvr --replSet r2/121.5.167.13:27021-- 1.登录任意节点-- 2. use admin-- 3. 执行config = { _id:"r2", members:[{_id:0,host:"121.5.167.13:27021"},{_id:1,host:"121.5.167.13:27022"},]}rs.initiate(config);//初始化# 4.启动3个config服务> ./mongod --port 27023 --dbpath ../cluster/shard/config1 --bind_ip 0.0.0.0 --replSet config/[121.5.167.13:27024,121.5.167.13:27025] --configsvr> ./mongod --port 27024 --dbpath ../cluster/shard/config2 --bind_ip 0.0.0.0 --replSet config/[121.5.167.13:27023,121.5.167.13:27025] --configsvr> ./mongod --port 27025 --dbpath ../cluster/shard/config3 --bind_ip 0.0.0.0 --replSet config/[121.5.167.13:27023,121.5.167.13:27024] --configsvr# 5.初始化 config server 副本集- `登录任意节点 congfig server`> 1.use admin > 2.在admin中执行config = { _id:"config", configsvr: true,members:[{_id:0,host:"121.5.167.13:27023"},{_id:1,host:"121.5.167.13:27024"},{_id:2,host:"121.5.167.13:27025"}]}> 3.rs.initiate(config); //初始化副本集配置 # 6.启动 mongos 路由服务> ./mongos --port 27026 --configdb config/121.5.167.13:27023,121.5.167.13:27024,121.5.167.13:27025 --bind_ip 0.0.0.0 # 7.登录 mongos 服务> 1.登录 mongo --port 27026> 2.use admin> 3.添加分片信息db.runCommand({ addshard:"r0/121.5.167.13:27017,121.5.167.13:27018","allowLocal":true });db.runCommand({ addshard:"r1/121.5.167.13:27019,121.5.167.13:27020","allowLocal":true });db.runCommand({ addshard:"r2/121.5.167.13:27021,121.5.167.13:27022","allowLocal":true });> 4.指定分片的数据库db.runCommand({ enablesharding:"baizhi" });> 5.设置库的片键信息db.runCommand({ shardcollection: "baizhi.users", key: { _id:1}});db.runCommand({ shardcollection: "baizhi.emps", key: { _id: "hashed"}})
完结
【编程不良人】MongoDB最新实战教程学习笔记相关推荐
- 【编程不良人】快速入门SpringBoot学习笔记06---RestFul、异常处理、CORS跨域、Jasypt加密
1. RestFul 配套视频:[编程不良人]2021年SpringBoot最新最全教程_哔哩哔哩_bilibili 1.1 引言 REST全称是(Resources) Representationa ...
- 【编程不良人】快速入门Spring学习笔记08---事务属性、Spring整合Structs2框架(SM)、Spring整合Mybatis+Struts2(SSM)、Spring注解、SSM注解式开发
1. 事务属性 1.1 事务传播属性 配套视频:[编程不良人]快速入门Spring,SpringBoot.SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili # ...
- 《Python编程:从入门到实战》学习笔记(第2版) 第1-2章 起步变量和简单数据类型
[写在前面]为进一步提高自己的python代码能力,打算把几本经典书籍重新过一遍,形成系统的知识体系,同时适当记录一些学习笔记,我尽量及时更新!先从经典的<Python编程:从入门到实战> ...
- 【编程不良人】SpringSecurity实战学习笔记07---授权
配套视频:61.授权之授权核心概念_哔哩哔哩_bilibili 什么是权限管理? 权限管理核心概念 Spring Security权限管理策略 基于URL地址方式实现的权限管理 基于方法实现的权限管理 ...
- OceanBase 从0到1数据库内核实战教程学习笔记 - 3.OceanBase基础架构和开发技巧
这篇文章主要介绍王泽林老师分享的 <OceanBase 的基础架构和开发技巧>.如果您看过第一篇文章的对应视频,会发现整个系列主要分为 MiniOB 和 OceanBase 两个系列,本篇 ...
- OceanBase 从0到1数据库内核实战教程学习笔记 - 8.MiniOB Drop Table 解析
本文将带领大家从源码层面过一下 Drop Table 的实现,下面我们先回顾一下之前介绍过的 MiniOB 框架,SQL 语句的解析过程中,当前已经实现的只有 Parser.Resolver 和 Ex ...
- Hadoop 从入门到精通----leo学习编程不良人视频的笔记--part01
编程不良人原版笔记 - https://blog.csdn.net/wei198621/article/details/111280555 part 01 hadoop 集群的搭建 – https:/ ...
- jwt实战详解--B站编程不良人视频笔记
文章目录 前言 一.什么是JWT 二.JWT能做什么 1.授权 2.信息交换 三.为什么使用JWT 四.JWT的结构是什么 五.使用JWT 1.引入依赖 2.生成token 3.根据令牌和签名解析数据 ...
- Hadoop 从入门到精通----编程不良人笔记
编程不良人原版笔记 - https://blog.csdn.net/wei198621/article/details/111280555 part 01 hadoop 集群的搭建 – https:/ ...
最新文章
- 辽宁交通高等专科学校计算机专业,辽宁省交通高等专科学校怎么样 全国排名第几...
- android 蓝牙 不休眠_全新便携蓝牙键盘 雷柏XK100带来高效办公新体验
- Verilog功能模块——取滑动平均值(使用寄存器组)
- 前端入门--解决问题的一些方法
- 机器学习-分类算法-逻辑回归13
- 离散数学及其应用上的一个问题
- 设计模式工厂方法模式
- StudentManager-java+mysql学生管理系统
- Git和GitHub快速入门
- AndroidStudio使用入门
- 计算机网络实验报告校园网,校园网规划与设计实验报告.docx
- 软件开发质量的双保险 — 2.业务设计验证与业务用例
- 字符串匹配BF/RK/BM/KMP算法
- 那个linux系统自带应用商店,如何在荣耀笔记本(Linux版)中拥有deepin应用商店?...
- 神奇的canvas——巧用 canvas 为图片添加水印
- 关于bacula网络备份软件的安装以及配置1
- HDOJ--1248--寒冰王座
- Geohot使用绿雨的BETA4越狱iPhone4 4.1固件详细教程
- 用envi对遥感影像进行规则裁剪
- GAN的量化评估方法——IS和FID,及其pytorch代码
热门文章
- 图之邻接表详解(C语言版)
- 读博碎碎念3:当前读博焦虑的事情
- 《脑的争论:先天还是后天?》约翰·E.道林阐述脑发育成熟老化研究进展(11400字)(附1书1文PDF公号发“脑的争论”下载)
- 麓言信息专业ui设计
- Android Menu item位置,Android MenuItem自定义布局
- 5555~面吸多久才能看到效果,面吸后多久能消肿,心急啊
- 【区块链108将】对话张斗:TFBOYS幕后推手,他们要出海打造首个区块链男团FBI
- 7月起韩国日访问量超10万人次网站实行实名制
- 杰理之普通无线麦方案【篇】
- Not all slots covered! Only 10922 slots are available