# study-mongodb-redis **Repository Path**: liu_laughs/study-mongodb-redis ## Basic Information - **Project Name**: study-mongodb-redis - **Description**: NOSQL数据库入门到实战: 结合实践案例,以任务为驱动,对Mongodb、Redis数据库技术进行梳理,让开发者快速掌握Mongodb和Redis数据库。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: https://www.ossbar.com - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 17 - **Created**: 2022-11-18 - **Last Updated**: 2022-11-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # study-nosql Mongodb、Redis数据库入门到实战: 结合实践案例,以任务为驱动,对Mongodb、Redis数据库技术进行梳理,让开发者快速掌握Mongodb和Redis数据库。 # 教材及素材获取 https://www.ossbar.com/#/productDetail?proData=%7B%22productId%22%3A315,%22skuId%22%3A972,%22shopId%22%3A138%7D # MongoDB是什么  MongoDB并非芒果的意思,而是源于 Humongous(巨大)一词。中文叫盲狗db MongoDB是面向文档的数据库,不是关系型数据库。它将原来**‘行’(row)的概念换成了更加灵活的‘文档’(document)模型**。面向文档的方式可以将文档和数组内嵌进来,所以用一条记录就可以表示很复杂的层次关系。 MongoDB没有模式,文档的键不会事先定义也不会固定不变。 Mongodb主要由文档(Document)、集合(Collection)、数据库(Database)三部分组成。 一个MongoDB实例,由多个数据库(Database)组成;一个数据库,由多个集合(Collection)组成;一个集合,又由多个文档组成。注意Mongodb单个文档大小上限为16MB,确保不会使用过多的内存RAM或在传输过程中占用过多的带宽。为了存储更大的文档,Mongodb提供了GridFS。 ![image](https://user-images.githubusercontent.com/110378589/194085125-1c6a74ca-00c1-4866-8da2-64f1f85a2fa1.png) ## 程序员注重对象,您的数据库也是。 MongoDB 是一个文档数据库,即在类似 JSON 的文档内存储数据。我们认为面对数据,这种方法非常自然,比传统的排/列模型更加直观和强大。 ## 丰富的 JSON 文档  ●  自然、高效的数据处理方法。  ●  支持将数组和嵌套对象存储为值。  ●  支持灵活、动态结构。 ## 强大的查询语言  ●  查询语言丰富和直观,支持通过任何字段进行筛选和排序,而不受其在文档内的嵌套方式影响。  ●  支持聚合和其他现代使用案例,如基于地理的搜索、图搜索和文本搜索。  ●  查询本身是 JSON 格式,因此很容易进行组合。无需串联字符串即可动态生成 SQL 查询。 ## MongoDB特性  MongoDB的3大技术特色如下所示: 除了上图所示的还支持: 二级索引、动态查询、全文搜索 、聚合框架、MapReduce、GridFS、地理位置索引、内存引擎 、地理分布等一系列的强大功能。 但是其也有些许的缺点,例如:   ●  多表关联: 仅仅支持Left Outer Join   ●  SQL 语句支持: 查询为主,部分支持   ●  多表原子事务: 不支持   ●  多文档原子事务:不支持   ●  16MB 文档大小限制,不支持中文排序 ,服务端 Javascript 性能欠佳 ## MongoDB适用场景 MongoDB的应用已经渗透到各个领域,比如游戏、物流、电商、内容管理、社交、物联网、视频直播等,以下是几个实际的应用案例:     ●    游戏场景:使用MongoDB存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新。     ●    物流场景:使用MongoDB存储订单信息,订单状态在运送过程中会不断更新,以MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。     ●    社交场景:使用MongoDB存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。     ●    物联网场景:使用MongoDB存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。     ●    视频直播:使用MongoDB存储用户信息、礼物信息等。 ![image](https://user-images.githubusercontent.com/110378589/194083181-4772c80d-7117-4e45-b698-4c5f738e0d01.png) # MongoDB的安装和配置 ## 安装前的准备 ### 1.芒果数据库官网地址:https://www.mongodb.com/ 备用下载链接:http://dl.mongodb.org/dl/win32/x86_64 ### 2.选择合适的Mongodb社区版或企业版 下载可以选择 zip 格式或者 msi 格式,msi 格式就是下一步、下一步安装。我们讲解 zip格式。 ### 3.解压缩这个文件夹,建议不要有中文路径 ## 安装说明 ### 1. 文件配置 进入解压后的文件夹,新建data和log文件夹,并在log文件夹下,新建mongod.log空文件 新建mongod.conf文件与bin文件夹同级 mongod.conf写入以下内容 ![image](https://user-images.githubusercontent.com/110378589/194069719-e2f369a5-f2c7-4c27-b922-9ba7e2cdfd37.png) 注:dbpath和logpath根据自己的具体路径进行修改 ### 2. 安装 开始---运行--cmd (ctrl+shift+Enter)调出windows终端,在mongodb解压目录的bin目录下执行如下命令:例如 mongod --config D:\mongodb-win32-x86_64-windows-5.0.11\mongod.conf--install --serviceName mongodb 执行后的结果可以在控制面板---管理工具--服务列表中查看到服务名为mongodb的进程。 注:在cmd操作下执行一定要以管理员身份运行,否则可能造成安装失败 正常情况下执行后窗口没有任何反应,其实是正常在生成data下默认的几个数据库文件,可以查看是否已经在data目录下生成初始化文件。 ### 3. 查看服务及启动服务  启动/停止mongodb: net start/stop mongodb ## 客户端工具推荐 MongoDB客户端工具推荐: ### 1、NoSQL Manager for MongoDB Freeware https://www.mongodbmanager.com/download ![image](https://user-images.githubusercontent.com/110378589/194070651-0eb146ab-9932-44e6-808b-40517f095bd3.png) ### 2、Navicat Premium全能数据库工具(强烈推荐) Navicat Premium 是一套数据库开发工具,让你从单一应用程序中同时连接 MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite 数据库。它与 Amazon RDS、Amazon Aurora、Amazon Redshift、Microsoft Azure、Oracle Cloud、MongoDB Atlas、阿里云、腾讯云和华为云等云数据库兼容。你可以快速轻松地创建、管理和维护数据库。 默认情况下Navicat 不显示mongodb默认三个数据库,需要显示隐藏的项目 ![image](https://user-images.githubusercontent.com/110378589/194070888-f5197a6f-0841-41ec-8a7e-0fad9fa40e0e.png) ![image](https://user-images.githubusercontent.com/110378589/194070792-26c9c4bd-3400-4eca-b5db-34704c972f3f.png) ### 3、Robo 3T https://robomongo.org/download ## Mongodb的基本操作 ### Mongodb数据类型 首先我们要先了解一下MongoDB中有什么样的数据类型: Object  ID :Documents 自生成的 _id 这是MongoDB生成的类似关系型DB表主键的唯一key,具体由24个字节组成: 0-8字节是时间戳, 9-14字节的机器标识符,表示MongoDB实例所在机器的不同; 15-18字节的进程id,表示相同机器的不同MongoDB进程。 19-24字节是计数器 注意如果插入文档时指定_id的值则MongoDB就不会赋值Object ID,但要注意_id的唯一性 获取_id可以执行ObjectId(); 例如: "_id" : ObjectId("5b151f8536409809ab2e6b26") #"5b151f85" 代指的是时间戳time,这条数据的产生时间 #"364098" 代指某台机器的机器码machine,存储这条数据时的机器编号 #"09ab" 代指进程ID,PID多进程存储数据的时候,非常有用的 #"2e6b26" 代指计数器INC,这里要注意的是,计数器的数字可能会出现重复,不是唯一的 #以上四种标识符拼凑成世界上唯一的ObjectID #只要是支持MongoDB的语言,都会有一个或多个方法,对ObjectID进行转换 #可以得到以上四种信息 #注意:这个类型是不可以被JSON序列化的   ● String: 字符串,必须是utf-8   ● Boolean:布尔值 true 或者false 这里首字母是小写的      ● Integer:整数 Int32 Int64 你们就知道有个Int就行了,一般我们用Int32   ● Double:浮点数 没有float类型,所有小数都是Double   ● Arrays:数组或者列表 多个值存储到一个键:这个数据类型就是字典   ● Null:空数据类型 , 一个特殊的概念,None Null   ● Timestamp:时间戳   ● Date:存储当前日期或时间unix时间格式 我们一般不用这个Date类型,时间戳可以秒杀一切时间类型 ### 数据类型转换 1、int转换为string类型 ``` String(); db.collectionName.find().forEach(function(x) { x.FieldName = x.FieldName.toString(); db.collectionName.save(x); }); db.emp.find({sal:{$lt:String(2000)}}); ``` 2、string转换为Date类型 ``` ISODate()、 db.collectionName.find().forEach(function(x) { x.FieldName = new ISODate(x.FieldName ); db.collectionName.save(x); }); ```  3、string转换为int类型 ``` 常用有:Number(),NumberInt,NumberLong,NumberDEcimal //string转为int类型 db.collections.find().forEach( function (x) { x.ise= NumberInt (x.ise); db.collections.save(x); }); ``` 4、Mongodb库中已存在的数据的类型转换 ``` db.emp.updateMany({ sal: { $exists: true }}, [{$addFields:{ sal: { $toDouble: "$sal" }}}] ); ``` ###  数据库操作 MongoDB 中默认的数据库为 test,如果没有创建新的数据库,集合将存放在 test 数据库中。 #### 【查看数据库】 使用show dbs来查看数据库 ``` show dbs 或 show databases; ``` #### 【创建/切换】  使用use命令来切换/创建数据库,会发现创建的数据库并不在数据库的列表中, 要显示它,需要向数据库插入一些数据 use db_name #### 【显示当前数据库】 使用db命令来显示/查看当前数据库,效果等同于 db.getName() ``` db ``` #### 【删除数据库】 这将删除当前所选数据库。 如果没有选择任何数据库,那么它将删除默认的’test‘数据库 ``` db.dropDatabase() ``` ###  集合操作 #### 创建集合 db.createCollection(name, options) 参数说明: name: 要创建的集合名称 options: 可选参数, 指定有关内存大小及索引的选项 1 首先进入数据库 use 数据库名称 2 创建集合 db.creareCollection('集合名称') 创建集合有一些可选参数 size、capped都是在固定集合上使用的,我们一般将固定集合使用在日志上面,之前的日志文件难以维护,还要定期去处理。 有了固定集合当日志达到最大的时候他会覆盖最早的日志,这样减少了日志维护的资源; ``` db.createCollection("role",{capped:true,autoIndexId:true,size:6100000}); db.createCollection("student",{capped:true,autoIndexId:true,size:6100000}); db.createCollection("user"); ``` 这样就创建一个固定大小的集合,默认_id创建一个索引,在MongoDB里面每一行数据的_id都是唯一的。 max是该集合最大的文档数,也就是可以插入数据的上限; #### 删除集合 db.user.drop() 删除user集合 #### 查看集合 db.getCollectionNames():获取当前 db 的所有集合,以数组形式显示 show collections:获取当前 db 的所有集合,以列表(换行)形式显示 ``` show collections ``` #### 集合的重命名 ``` db.role.renameCollection('user') ``` ### 文档操作  MongoDB的数据定义格式和JSON的数据定义格式是一样的,但是在MongoDB中我们把他称之为BSON(Binary JSON)是一种类json的一种二进制形式的存储格式。他的数据格式是非常丰富的,比如我们在MySQL中要联系两站表的关系我们会创建一个表,里面存放他们的关系。但是在MongoDB里面我们可以放在同一个文档里面,我们定义一个数组类型的属性,这个数组就可以存放他们之间的关系,只需要两个而不是三个。 #### 插入文档 要将数据插入到 MongoDB 集合中,需要使用 MongoDB 的 insert()或save()方法,还有insertOne()或insertMany()方法  insert()命令的基本语法如下 ``` db.COLLECTION_NAME.insert(document) ``` save():如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne() 或 db.collection.replaceOne() 来代替。 insert(): 若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据。 在插入的文档中,如果不指定_id参数,那么 MongoDB 会为此文档分配一个唯一的ObjectId。_id为集合中的每个文档唯一的12个字节的十六进制数 _id,又称为ObjectId是一个12字节的BSON类型字符串。按照字节顺序依次代表: ``` db.course.insert({ "name" : "数学", "type" : "major" }) ``` 向课程表里插入一条数据 一次性插入多条数据db.collection.insertMany()  ``` /* 插入多条记录 */ db.student.insert([ { "stu_name" : "小明", "stu_number" : "2013001", "stu_sex" : "男", "course" : [ ObjectId("5bb82bb3627eb5e25bead053"), ObjectId("5bb82c5f627eb5e25bead054"), ObjectId("5bb82c5f627eb5e25bead055"), ObjectId("5bb82c5f627eb5e25bead057"), ObjectId("5bb82c5f627eb5e25bead058") ], }, { "stu_name" : "小红", "stu_number" : "2013002", "stu_sex" : "女", "course" : [ ObjectId("5bb82bb3627eb5e25bead053"), ObjectId("5bb82c5f627eb5e25bead054"), ObjectId("5bb82c5f627eb5e25bead055"), ObjectId("5bb82c5f627eb5e25bead056"), ObjectId("5bb82c5f627eb5e25bead058") ], } ]) ``` 就像JSON一样。一次封装多个数据我们就用数组包裹起来就可以了,我们直接在学生表里面关联课程的信息,course就是我们学生所选的课程。 同样我们也可以定义一个变量 ``` document1=( { "stu_name" : "小明", "stu_number" : "2013001", "stu_sex" : "男", "course" : [ ObjectId("5bb82bb3627eb5e25bead053"), ObjectId("5bb82c5f627eb5e25bead054"), ObjectId("5bb82c5f627eb5e25bead055"), ObjectId("5bb82c5f627eb5e25bead057"), ObjectId("5bb82c5f627eb5e25bead058") ], }, { "stu_name" : "小红", "stu_number" : "2013002", "stu_sex" : "女", "course" : [ ObjectId("5bb82bb3627eb5e25bead053"), ObjectId("5bb82c5f627eb5e25bead054"), ObjectId("5bb82c5f627eb5e25bead055"), ObjectId("5bb82c5f627eb5e25bead056"), ObjectId("5bb82c5f627eb5e25bead058") ] }); ``` 再执行db.student.insert(document1); 还有一种插入的方法: ``` db.student.save( { "stu_name" : "小峰", "stu_number" : "2013009", "stu_sex" : "男", "course" : [ ObjectId("5bb82bb3627eb5e25bead053"), ObjectId("5bb82c5f627eb5e25bead054"), ObjectId("5bb82c5f627eb5e25bead055"), ObjectId("5bb82c5f627eb5e25bead057"), ObjectId("5bb82c5f627eb5e25bead058") ], } ) ``` save也可以插入数据,save操作和insert操作的区别在于,save在遇到_id相同的插入数据时候,会覆盖原来的,而insert会提示错误。 shell的for循环批量插入文档:一次插入多条数据 1、先创建数组 2、将数据放在数组中 3、一次 insert 到集合中 ``` /* 插入单个文档练习 */ db.user.insert( { "name":"liwei", "tel":18843436650 } ); db.user.insert( { "name":"liwei", "tel":18843436650, "yz":"100" } ); /* 插入多个文档练习 */ db.user.insertMany( [ { "name":"longdage", "sex":1, "jushu":"good" }, { "name":"gaoluofeng", "zhiwu":"1ge", "jushu":"yiliu" } ] ); /* 批量插入多个文档练习 */ var arr = []; for(var i=1 ; i<=20000 ; i++){ arr.push({name:"小峰"+i}); } db.user.insert(arr); ``` #### 更新文档 db.student.update({ 查询的条件, 更新的语句, 附加的参数 }) 附加的参数 构造更新操作前的准备工作,插入测试数据 ``` db.student.insertMany([ { "stu_name" : "小张", "stu_number" : "2013003", "age":18 }, { "stu_name" : "小张", "stu_number" : "2013002", "age":28 }, { "stu_name" : "小张三", "stu_number" : "2013004", "age":38 }] ); ``` 区分:update默认情况下是只修改一个文档,等同updateOne,如果需要修改多个可以使用multi:true属性 ``` db.collection.update(query, update); db.student.update( { "stu_name" : "小张" }, { $set : {"stu_name" : "小张二"} } ) db.collection.updateOne(query, update); db.student.update( { "stu_name" : "小张" }, { $set : {"stu_name" : "小张一"} } ) ``` 修改多个文档 ``` db.student.update( { "stu_name": "小张" }, { $set: { "stu_name": "小张二" } }, { multi: true } ) ``` db.collection.updateMany(query, update); $set : 用来指定一个键的值 $unset : 删除指定一个属性 $inc : 增加和减少(increase) $push : 向数组尾部追加元素 $addToSet : 添加时避免重复,  例如: db.user.update({"_id": ObjectId("....")}, {$addToSet: {"emails": "sky3hao@163.com"}}) $addToSet 和 $each 组合起来,可以添加多个不同的值. $pop : 从数组某一端删除元素 $pull : 基于条件来删除数组元素 ``` test.update({'name':'foobar'},{$set:{'age':36}}) <==> update test set age=36 where name='foobar' db.test.update({'name':'foobar'},{$inc:{'age':3}}) <==> update test set age=age+3 where name='foobar' ``` and条件,挨着写默认就是and ``` db.student.update( { "stu_name" : "小张", "stu_number" : "2013003", }, { $set : {"stu_name" : "小张二"} } ) ``` or条件,要出现$or的关键字 ``` db.student.update( { $or : [ {"stu_name" : "小张二"}, {"stu_number" : "2013003"} ], }, { $set : {"stu_name" : "小张"} } ) $inc db.student.update( { "stu_number" : "2013001" }, { $inc : {"mark" : 1}//自增1,为负数的时候就是减 } ); ``` 大于一个数据或小于一个数 ``` db.student.update( { "stu_number" : {$gte:"2013001",$lte:"2013002"} }, { $inc : {"mark" : 1}//自增1,为负数的时候就是减 } ); ``` 布尔运算符 1 $ne : 不等于 2 $not : 不匹配结果 3 $nor : 所有的条件都不匹配 4 $exists : 判断元素是否存在 $exists db.student.find( { "stu_number" : {$exists:true} } ); 返回这个字段存在的所有记录,当为false的时候结果就是相反; #### 删除文档 db.student.remove({ 条件 },属性) ``` db.student.remove( { "_id":ObjectId("5bb83384627eb5e25bead061") } ) ``` 另外删除单个和多个文档: /* 删除单个文档 */ ``` db.student.deleteOne(); ``` /* 删除多个文档 */ ``` db.student.deleteMany(); ``` /* 可以删除单个也可以多个如果设置true表示删除一个,否则多个*/ ``` db.student.remove(); ``` /* 删除集合中所有文档:清空 */ ``` db.student.remove({}); ``` /* 或使用性能最高的 */ ``` db.student.drop(); ``` #### 查询文档 掌握选择器(selector)  MongoDB的查询选择器就像SQL代码中的where语句。因此您可以用它在集合中查找,统计,更新或是删除文档。选择器就是一个JSON对象,最简单的形式就是{},用来匹配所有的文档(null也可以)。如果我们需要找到所有雌性的独角兽(unicorn),我们可以用选择器{gender:'f'}来匹配。 要从MongoDB集合查询数据,需要使用MongoDB的find()方法,默认返回结果中的前20条文档,输入"it"显示接下来的20条文档。  find()命令的基本语法如下: db.COLLECTION_NAME.find(document) find()方法将以非结构化的方式显示所有文档 数据准备 ``` db.student.insertMany([ { "stu_name": "小李子", "stu_number": "2013003", "age": 19.5, "sex": "男" }, { "stu_name": "小李子", "stu_number": "2013002", "age": 9.5, "sex": "男" }, { "stu_name": "小李子", "stu_number": "2013004", "age": 4.5, "sex": "男" }, { "stu_name": "小张", "stu_number": "2013003", "age": 18, "sex": "女" }, { "stu_name": "小张", "stu_number": "2013002", "age": 28, "sex": "女" }, { "stu_name": "小张三", "stu_number": "2013004", "age": 38, "sex": "女" }, { "stu_name": "小李", "stu_number": "2012001", "age": 19.5, "sex": "男" }, { "stu_name": "小李", "stu_number": "2012002", "age": 29.5, "sex": "女" }, { "stu_name": "小李", "stu_number": "2012003", "age": 39.5, "sex": "女" } ]); ``` 比较运算符 查询的条件有: 等于equal;不等于not equal,小于less than,小于或等于equal or less than,大于greater than,大于或等于equal or greater than。 $not ``` db.student.find( { 'stu_number' : {$not : {$ne : "2013002"}} } ).pretty() ``` 这种情况下也会返回没有stu_number的字段,和$gt这些比较运算符是不同的,他们只会返回有的字段 范围运算符 $in,不在集合里面我们就用$nin ``` db.student.find( { 'stu_number' : { $in : ["2013001","2013002"]} } ).pretty() ``` 和Mysql的where in是一样的效果,他会查出2013001和002的数据 模糊查询:正则表达式 在mongoDB里面我们的模糊查询是按照正则表达式来进行匹配的 ``` db.student.find( { "stu_number":{$regex:/^2013/} } ) ``` 我们要查询一个数组里面一个字段的值,我们用点进行连接 ``` { "userInfo" : { "name" : "张三", "age" : 28 } } ``` 我们要查询name等于张三的信息 db.student.find({"userInfo.name":"张三"}) JavaScript查询 ``` db.student.find( { "$where" : "function () {return this.stu_number == '2013001'}" } ) ``` 排序 1:升序 -1:降序 语法: db.stu.find().sort({字段:1}) 举例: ``` db.student.find().sort({"stu_number":-1}).pretty() ``` /* #多属性排序sort升序值1,降序为-1 ``` db.student.aggregate([{$sort:{age:-1}},{$sort:{stu_name:-1}}]); db.student.find().sort({age:-1},{stu_name:-1}).pretty(); ``` */ /*显示10条数据*/ ``` db.student.find().sort({age:-1},{stu_name:-1}).limit(10).pretty(); db.student.find().sort({age:-1},{stu_name:-1}).limit(10).skip(2).pretty(); ``` 限制 ``` db.student.find().sort({"stu_number":-1}).limit(5).pretty() ``` 限制显示5条数据 跳过 ``` db.student.find().sort({"stu_number":-1}).limit(5).skip(2).pretty() ``` #跳过前两个并且显示5条数据 我们所看到的限制、跳过和Mysql的limit一样,限制就是第一个参数,跳过就是第二个参数偏移量。 查询返回特定的字段 ``` db.student.find({},{'stu_number':0,}).sort({"stu_number":-1}).limit(5).skip(2).pretty() ``` 当我们stu_number为0的时候,返回除了stu_number以外的数据,如果为1只返回stu_number一个字段的数据。 统计个数 db.stu.find(条件).count() db.stu.count({条件}) 消除重复 db.stu.distinct(去重字段, {条件}) 聚合 aggregate 表达式 $sum $avg $min $max $push: 数组 $first $last $$ROOT: 将文档内容加入到结果集的数组中 /*聚合管道操作*/ /*性别分组并统计男女数*/ ``` db.student.aggregate({ $group: { _id:"$sex", num:{$sum:1} } }); ``` /*求文档数*/ ``` db.student.find().count(); ``` /*求属性值 最大*/ ``` db.student.aggregate({ $group: { _id:"$id", max_value:{$max:"$age"} } }); ``` /*求属性值 最小*/ ``` db.student.aggregate({ $group: { _id:"$id", min_value:{$min:"$age"} } }); ``` /*求属性值 平均值 */ ``` db.student.aggregate({ $group: { _id:"$id", avg_value:{$avg:"$age"} } }); ``` #### 任务一 Mongodb命令操作实践练习 MongoDB综合练习{CRUD(Create、Read、Update、Delete)中的四个操作} 1.创建(进入)mytest数据库 2.向数据库的users集合插入一个username为张三的文档。 3.检查当前数据库和和当前集合有没创建成功。 4.查询users集合当中的文档。 5.统计当前数据库中users集合中的文档数量。 6.查询数据库users集合中username为张三的文档。 7.向数据库users集合中的username为张三的文档,添加一个address属性,属性值为深圳龙岗。 8.将username: "张三" 替换为 username:"李四"。 9.删除username为李四的文档的address属性。 10.向username为"李四"的文档中添加一个hobby:{cities:["上海","北京","广州"],movies:["卡通","惊悚","科幻"]}属性。(嵌套文档操作) 11.查询李四爱好movie中卡通的嵌套文档。 12.向李四中添加一个新的电影类型:爱情。 13.删除喜欢北京的用户。 14.清空users集合。 15.删除users集合(默认会把数据库也给删除了)。 16.新建一个myTest数据库,通过for循环向numbers集合中插入200条数据(数据即文档),并且统计当前数据数量是否够数。(tip:要点击文件刷新) 17.如果我们想向numbers集合插入20000条数据而不仅仅是200条数据呢,有没有性能高一点的法子?因为for遍历循环,意味着insert方法要执行3000次,性能肯定是差的了。 18.查询numbers集合中num为500的 文档。 19.查询numbers集合中num大于500的文档。 20.查询numbers集合中num小于30的文档。 21.查询numbers集合中num大于40小于50的文档。 22.查看numbers集合中的前10条数据。 23.查看numbers集合中的第11-20条的数据。 #### 任务一 Mongodb命令操作实践练习答卷 1.创建(进入)mytest数据库 ``` use mytest; ``` 2.向数据库的users集合插入一个username为“张三”的文档。 ``` db.users.insert({username:"张三"}); ``` 3.检查当前数据库和和当前集合有没创建成功。 ``` show dbs | show database show collections ``` 4.查询users集合当中的文档。 ``` db.users.find(); db.users.find({ }); ``` 5.统计当前数据库中users集合中的文档数量。 ``` db.user.find().count(); ``` 6.查询数据库users集合中username为张三的文档。 ``` db.users.find({username: "张三"}); ``` 7.向数据库users集合中的username为张三的文档,添加一个address属性,属性值为湖南长沙。 ``` db.users.update( {username: "张三"}, {$set:{address: "湖南长沙"}} ) ``` 8.将username: "张三" 替换为 username:"李四"。 ``` /*单个文档替换*/ db.users.replaceOne({username:"张三"},{username:"李四"}) /*多个文档替换:建议使用save方法直观明了*/ db.users.find({ username: '李四' }).forEach (function(item) { item.username=item.username.replace('李四','张三'); db.users.save(item); }); db.users.find({ username: '李四' }).forEach (function(item) { username1=item.username; username1=username1.replace('李四','张三'); db.users.update({username:'李四'},{$set:{username:username1}}); }); ``` 9.删除username为李四的文档的address属性。 ``` db.users.update({username:"李四"},{$unset:{address:1}}) ``` 10.向username为"李四"的文档中添加一个hobby:{cities:["上海","北京","广州"],movies:["卡通","惊悚","科幻"]}属性。(嵌套文档操作) ``` db.users.update({username:'李四'},{$set:{hobby:{cities:["上海","北京","广州"],movies:["卡通","惊悚","科幻"]}}}); ``` 11.查询李四爱好movie中卡通的嵌套文档。 MongoDB支持直接通过内嵌文档的属性进行查询,如果要查询内嵌文档则可以通过.的形式来匹配,此时的属性名必须使用引号。 ``` db.users.find({'hobby.movies':"卡通"}) ``` 12.向李四中添加一个新的电影类型:爱情。 $push 用于向数组中添加一个新对元素(元素可以重复添加) $addToSet 也是向数组中添加一个新对元素(如果数组中的元素已经存在,则不会重复添加) ``` db.users.update({username:'李四'},{$push:{'hobby.movies':'爱情'}}); db.users.update({username:"李四"},{$addToSet:{"hobby.movies":"爱情"}}) ``` 13.删除喜欢北京的用户。 ``` db.users.remove({"hobby.cities":"北京"}) ``` 14.清空users集合。 ``` db.users.remove({}) ``` 15.删除users集合(默认会把数据库也给删除了)。 ``` db.users.drop() ``` 16.新建一个myTest数据库,通过for循环向numbers集合中插入200条数据(数据即文档),并且统计当前数据数量是否够数。 ``` use myTest; for (var i=1 ; i<=200 ; i++) { db.numbers.insert({num:i}) } db.numbers.find().count() ``` 17.如果我们想向numbers集合插入20000条数据而不仅仅是200条数据呢,有没有性能高一点的法子?因为for遍历循环,意味着insert方法要执行20000次,性能肯定是差的了。 ``` var arr = []; for (var i=1 ; i<=20000 ; i++) { arr.push({num:i}) } db.numbers.insert(arr); db.numbers.find(); ``` 18.查询numbers集合中num为500的 文档。 ``` db.numbers.find({num:500}) 或者 db.numbers.find({num:{$eq:500}}) ``` 19.查询numbers集合中num大于500的文档。 ``` db.numbers.find({num:{$gt:500}}) ``` 20.查询numbers集合中num小于30的文档。 ``` db.numbers.find({num: {$lt:30}}); ``` 21.查询numbers集合中num大于40小于50的文档。 ``` db.numbers.find({num:{$gt:40,$lt:50}}); db.numbers.find({"$where":"this.num>40&&this.num<50"}); db.numbers.find({ "$and": [{ "$where": "this.num>40" }, { "$where": "this.num<50" }] }); ``` 22.查看numbers集合中的前10条数据。 ``` db.numbers.find({nums:{$lte:10}}) //当数据是有序的时候,可以使用这个方法。 或者使用limit()方法,设置数据显示的上限,限制显示数据条目。 db.numbers.find().limit(10) //无论数据是有序还是无序,皆可用limit()方法,即带条件的查询方式,实现的就是一种分页的功能。 你可以这样理解:limit(10)方法,1页显示10条数据。 ``` 23.查看numbers集合中的第11-20条的数据。 ``` db.numbers.find().skip(10).limit(10) skip()方法,用于跳过指定数量的数据。 skip(10),即跳过前面的前10条数据,limit(10)即1页显示10条数据。 ``` #### 任务二 Mongodb综合查询实战 独立完成以下练习 1.查询工资小于2000的员工 2.查询工资在1000-2000之间的员工 3.查询工资小于1000或大于2500的员工 4.查询财务部的所有员工 5.查询销售部的所有员工 6.查询所有mgr为7698的所有员工 7.为所有薪资低于1000的员工增加工资400元 #### 任务二 Mongodb综合查询实战答卷 1.查询工资小于2000的员工 ``` db.emp.find({sal:{$lt:2000}}) 或 db.emp.find({"$where":"this.sal<2000"}); ``` 2查询工资在1000-2000之间的员工 ``` db.emp.find({sal:{$lt:2000,$gt:1000}}) 或 db.emp.find({"$where":"this.sal<2000&&this.sal>1000"}); 或 db.emp.find({"$and": [   {"$where" : "this.sal > 1000"},   {"$where" : "this.sal < 2000"} ]}).pretty() ``` 3.查询工资小于1000或大于2500的员工 ``` db.emp.find({$or:[{sal:{$lt:1000}},{sal:{$gt:2500}}]}) 或 db.emp.find({"$or": [   {"$where" : "this.sal > 2500"},   {"$where" : "this.sal < 1000"} ]}).pretty() ``` 4.查询财务部的所有员工 ``` var depnum = db.dept.findOne({dname:"财务部"}).deptno db.emp.find({depno:depnum}) 或db.emp.find({depno:db.dept.findOne({dname:"财务部"}).deptno}) ``` 5.查询销售部的所有员工 ``` var depnum = db.dept.findOne({dname:"销售部"}).deptno db.emp.find({depno:depnum}) ``` 6.查询所有mgr为7698的所有员工 ``` db.emp.find({mgr:7698}) 或 db.emp.find({"$where":"this.mgr==7698"}) ``` 7.为所有薪资低于1000的员工增加工资400元 ``` db.emp.updateMany({sal:{$lte:1000}},{$inc:{sal:400}}) 或 db.emp.update({sal:{$lte:1000}},{$inc:{sal:400}},{multi:true}); db.emp.find({}) ``` ## Mongodb系统管理 ### 用户权限 角色-用户-数据库的安全管理方式 系统角色 root: 只在admin数据库的可用,超级账号/超级权限 Read: 允许用户读取指定数据库 readWrite: 允许用户读写指定数据库 ### 创建管理员用户 创建超级管理员 ``` use admin; db.createUser({ user:'admin', pwd:'123', roles:[{role:'root',db:'admin'}] }); ``` 创建普通用户 ``` use test; db.createUser({ user:'test', pwd:'123', roles:[{role:'readWrite',db:'test'}] }); ``` ### 修改和重置密码 按照以下规则设置账号名对应的新密码。 密码由大写字母、小写字母、数字、特殊字符中的至少三种组成,特殊字符为: !#$%^&*()_+= 密码长度为8~32位。 修改密码 切换至mongo的bin目录下,登录mongo mongo 登陆成功后,切换至admin表 (mongodb的所有用户都会存储在admin表中,所以需要切换至admin表再进行用户的修改) ``` use admin db.changeUserPassword('用户名','新密码'); db.auth('用户名','新密码'); ``` 可以退出exit验证 ,再次登录。 忘记密码 找到mongodb的配置文件mongod.conf,编辑配置文件将用户验证的配置项屏蔽 重启mongod,并登录mongo 这时候登录就不需要密码认证了,然后删除以前设置的用户 ``` use admin db.system.users.find() db.system.users.remove({}) ``` 重置密码 ``` db.createUser({user:'userName',pwd:'passWord',roles:[{"role":"root","db":"admin"}]}); db.auth('userName', 'passWord'); ``` 将配置文件的验证还原,重启mongod就可以了 ### 数据库备份和恢复 备份工具集下载和安装 要用到mongodump、mongorestore等工具时候发现原来下载的数据库文件缺失很多工具,需要单独下载 下载工具集: [输入链接说明](https://www.mongodb.com/try/download/database-tools) 下载完成后解压到mongodb/bin目录下即可 MongoDB数据备份 在Mongodb中我们使用mongodump命令来备份MongoDB数据。该命令可以导出所有数据到指定目录中。 mongodump命令可以通过参数指定导出的数据量级转存的服务器。 语法 mongodump命令脚本语法如下: mongodump.exe -h dbhost -d dbname -o dbdirectory 全部备份: mongodump.exe -h: MongoDB 所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017 -d: 需要备份的数据库实例,例如:test -o: 备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。 实例 在本地使用 27017 启动你的mongod服务。打开命令提示符窗口,进入MongoDB安装目录的bin目录输入命令mongodump: #数据库备份:找到mongodb数据库bin目录,例如: 在F:\database\MonogoDB\mongodb-win32-x86_64-windows-5.0.3\bin目录下 ``` mongodump.exe -h localhost:27017 -d db_student -o d:\ ``` MongoDB数据恢复 mongodb使用 mongorestore 命令来恢复备份的数据。 语法 mongorestore命令脚本语法如下 ``` >mongorestore -h <:port> -d dbname --gzip --host <:port>, -h <:port>: MongoDB所在服务器地址,默认为: localhost:27017 --gzip是压缩包格式,导入文档时必须要加此参数 -db , -d : 需要恢复的数据库实例 --drop: 恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦! :mongorestore 最后的一个参数,设置备份数据实例所在位置,例如:c:/data/dump/test。 你不能同时指定 和 --dir 选项,--dir也可以设置备份目录,整个例子:mongodump.exe -d test ./dump/test。 --dir: 指定备份的目录,例如 :./dump,备份目录内所有数据,所以-d不能使用,整个例子:mongodump.exe --dir ./dump 你不能同时指定 和 --dir 选项。 例如: ``` ``` mongorestore.exe -h localhost -d db_student --gzip C:\Users\zhujw\Documents\db_student ``` ## Mongodb持久化实战(Java) #### 任务三 java操作Mongodb数据库实战 见仓库源码:study-mongodb-template #### 任务四 springboot操作Mongodb数据库实战 见仓库源码:study-mongodb-springboot # redis简介 ## Redis(Remote Dictionary Server:远程字典服务)   ●    是完全开源并免费的,遵守BSD协议,是一个高性能的key-value数据库中   ●    Redis 与其他key-value 缓存产品有以下三个特点   ●    Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。   ●    Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。   ●    Redis支持数据的备份,即master-slave模式的数据备份 # Redis 优势   ●    性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。   ●    丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。   ●    原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。   ●    丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。   Redis是内存数据库,数据保存在内存中,访问速度快。MySQL是关系型数据库,功能强大,存储在磁盘中,数据访问速度慢。像memcached,MongoDB,Redis等,都属于No sql系列。 # Redis安装和配置 ## 下载安装     1. 官网:https://redis.io     2. 中文网:http://www.redis.net.cn/     3. 解压直接可以使用:         * redis.windows.conf:配置文件         * redis-cli.exe:redis的客户端         * redis-server.exe:redis服务器端 ### Windows下安装Redis步骤 1、下载和解压Redis-x64-3.2.100 Github下载地址:https://github.com/MicrosoftArchive/redis/releases 2、打开cmd指令窗口,输入你刚才解压的文件路径,然后输入以下命令 redis-server redis.windows.conf 3、安装Windows服务 redis-server --service-install redis.windows.conf 4、启动redis服务 #Redis常用的指令 #卸载服务: redis-server --service-uninstall #开启服务: redis-server --service-start 或net start redis #停止服务: redis-server --service-stop 或net stop redis ## 客户端工具推荐 1、Redis Desktop Manager 是一款跨平台开源 Redis ® 管理工具,RDM 是易于使用的 GUI 工具,可用于 Windows,Linux,MacOS,支持命令控制台操作,以及常用,查询key,rename,delete等操作。 下载地址:http://down.123520.net/dir/195471-41859118-4ed9f5 2、AnotherRedisDesktopManager 下载地址:https://github.com/qishibo/AnotherRedisDesktopManager 或国内:https://gitee.com/qishibo/AnotherRedisDesktopManager/releases/v1.5.0 # Redis数据类型及应用场景 ## Redis 数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。 ### String(字符串) 字符串类型是 Redis 中最基本的数据类型,一个 key 对应一个 value。可以存储二进制数据、图片和 Json 的对象。 string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。 string 类型的值最大能存储 512MB。 常用命令:get、set、incr、decr、mget等。 Redis还提供了下面一些操作:  获取字符串长度 往字符串append内容 设置和获取字符串的某一段内容 设置及获取字符串的某一位(bit) 批量设置一系列字符串的内容 ### Hash(哈希) Redis hash 是一个键值(key=>value)对集合。 Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。 常用命令:hget,hset,hgetall 等。 比如我们要存储一个用户信息对象数据,包含以下信息: 用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式: 方法一:将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。 方法二:是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,如下图: 也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题,很好的解决了问题。 ### List(列表) Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 ### Set(集合) Redis 的 Set 是 string 类型的无序集合。 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 sadd 命令 添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。 注意:以上实例中 rabbitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。 集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。 ### zset(sorted set:有序集合) Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。 zset的成员是唯一的,但分数(score)却可以重复。 ## Redis基本操作 ## 库与key的操作命令 key操作命令 获得符合规则的键名列表 KEYS pattern pattern 支持 glob 风格通配符: set 设置key的值语法 set key value ### set示例 ``` 127.0.0.1:6379> set name zhangsan OK 127.0.0.1:6379> set age 25 OK ``` get 获取key的值 get key ### get示例 ``` 127.0.0.1:6379> get name "zhangsan" ``` del 删除key del key ### del示例 ``` 127.0.0.1:6379> del name (integer) 1 ``` exists 判断key是否存在 exists key ### 判断key是否存在,存在返回1,不存在返回0 ### exists示例 ``` 127.0.0.1:6379> exists name (integer) 1 127.0.0.1:6379> exists title (integer) 0 ``` type 获取key类型 type key ### 获取key存储的值的类型 ### type示例 ``` 127.0.0.1:6379> type name string 127.0.0.1:6379> type age string ``` expire 设置key有效期 expire key ### 设置key的生命周期 # expire key 表示以秒为单位设置声明周期 ### expire示例 ``` 127.0.0.1:6379[1]> expire login 60 (integer) 1 127.0.0.1:6379[1]> ttl login (integer) 47 ``` tll 查看key有效期 ttl key ### 查询key的生命周期 # 大于0 :生命周期单位为秒, # 等于-1:永久有效 # 等于-2:该key不存在 # pttl key表示秒为单位 ### ttl示例 ``` 127.0.0.1:6379> ttl name (integer) -1 127.0.0.1:6379> ttl title (integer) -2 ``` rename 重命名key rename key newkey ### 重命名key,如果newkey已经存在,修改后则替换新key的值 ### rename示例 ``` 127.0.0.1:6379> set title "redis test" OK 127.0.0.1:6379> exists title (integer) 1 127.0.0.1:6379> rename title biaoti OK 127.0.0.1:6379> get biaoti "redis test" ``` renamenx 重命名不存在的key renamenx key newkey ### 重命名key,如果newkey已经存在则不修改。 # nx表示not exists ### renamenx示例 ``` 127.0.0.1:6379> keys * 1) "biaoti" 2) "age" 3) "name" 127.0.0.1:6379> renamenx biaoti name (integer) 0 ``` persist 设置key永久有效 persist key ### 设置key永久有效 ### persist示例 ``` 127.0.0.1:6379> set login on OK 127.0.0.1:6379> expire login 60 (integer) 1 127.0.0.1:6379> ttl login (integer) 55 127.0.0.1:6379> persist login (integer) 1 127.0.0.1:6379> ttl login (integer) -1 ``` move 把key移动到其他库 move key db ### 把key移动到另一个数据库,db为整数 # 示例 库操作命令 dbsize 查看当前有多少个key dbsize ### 查看当前有多少个key ### dbsize示例 ``` 127.0.0.1:6379> dbsize 12 select 选择库 select db ``` ### 选择使用哪个数据库,db为整数 # 默认有16个数据库0~15,如果想修改数据库数量,修改redis.conf配置文件的databases值 ### select示例 ``` 127.0.0.1:6379> select 1 OK 127.0.0.1:6379[2]> select 15 OK ``` flushdb 删除选中数据库中的key flushdb ### 删除当前选择数据库中的所有key ### flushdb示例 ``` 127.0.0.1:6379[1]> keys * 1) "biaoti" 127.0.0.1:6379[1]> flushdb OK 127.0.0.1:6379[1]> keys * (empty list or set) ``` flushall 删除所有库的key flushall ### 删除所有数据库中的key ### flushall示例 ``` 127.0.0.1:6379[1]> flushall OK 127.0.0.1:6379[1]> select 0 OK 127.0.0.1:6379> keys * (empty list or set) ``` ## 字符串类型操作命令 1.字符串类型(String)常用命令: 2.命名建议:“对象类型:对象ID:对象属性”命名一个键,如:“user:1:friends”存储 ID 为 1 的用户的的好友列表。对于多个单词则推荐使用 “.” 进行分隔。 3.应用: (1)访问量统计:每次访问博客和文章使用 INCR 命令进行递增; (2)将数据以二进制序列化的方式进行存储。 set 设置kv、效期、判断key是否存在 set key value [ex 秒数]|[px 毫秒数] [nx]|[xx] # 设置kv时也可以设置有效期和判断key是否存在 # ex和px不要同时写,否则以后面有效期为准 # nx表示key不存在时执行操作 # xx表示key存在时执行操作 ### set示例 ``` 127.0.0.1:6379> set name zhangsan OK ``` mset 一次性输入多个kv mset key1 value1 key2 value2...... # 一次性输入多个key-value ### mset示例 ``` 127.0.0.1:6379> mset x 1 y 2 z 3 OK 127.0.0.1:6379> keys * 1) "y" 2) "z" 3) "x" ``` setrange 修改偏移字节值为valuev setrange key offset value # 把字符串的偏移字节改为value # 如果偏移量大于字符长度,中间字符自动补0x00 ### setrange示例 ``` 127.0.0.1:6379> setrange name 5 *** (integer) 8 127.0.0.1:6379> get name "zhang***" ``` append 在key的值后面追加字符串 append key value # 在key的值后面追加value字符串 ### append示例 ``` 127.0.0.1:6379> set name zhangsan OK 127.0.0.1:6379> append name "@126.com" (integer) 16 127.0.0.1:6379> get name "zhangsan@126.com" ``` getrange 获取key值的部分内容 getrange key start stop # 获取key值的一部分内容 # start表示起始位置 # stop表示结束位置,可以为为负数,表示从最后数起 # start>length 空字符串 # stop>length 截取到结尾 ### getrange示例 ``` 127.0.0.1:6379> set title "hello world" OK 127.0.0.1:6379> getrange title 6 11 "world" 127.0.0.1:6379> getrange title 0 -7 "hello" ``` getset 设置新值返回旧值 getset key newvalue # 设置新值,并返回旧值 ### getset示例 ``` 127.0.0.1:6379> set login on OK 127.0.0.1:6379> get login "on" 127.0.0.1:6379> getset login off "on" 127.0.0.1:6379> get login "off" ``` incr/decr 指定key的值加/减1 incr/decr key # 指定key的值加/减1,返回结果 # key不存在时,自动创建并加减1 # key的值为字符串时无效 ### incr/decr示例 ``` 127.0.0.1:6379> set num 100 OK 127.0.0.1:6379> incr num (integer) 101 127.0.0.1:6379> decr num (integer) 100 ``` incrby/decrby 指定key的值加/减number incrby/decrby key number # 指定key的值加减number大小 ### incrby/decrby示例 ``` 127.0.0.1:6379> set num 100 OK 127.0.0.1:6379> incrby num 50 (integer) 150 127.0.0.1:6379> decrby num 100 (integer) 50 ``` incrbyfloat 指定key的值加浮点数 incrbyfloat key floatnumber # 指定key的值加浮点数 ### incrbyfloat示例 ``` 127.0.0.1:6379> set num 10 OK 127.0.0.1:6379> incrbyfloat num 0.5 "10.5" 127.0.0.1:6379> incrbyfloat num -1.5 "9" ``` setbit 设置二进制位上的值 setbit key offset value # 设置offset对应二进制位上的值 # 返回改位的旧值 # 如果offset过大则会在中间填充0 # offset最大为2^32-1,即512M ### setbit示例 ``` 127.0.0.1:6379> set letter A OK 127.0.0.1:6379> setbit letter 2 1 (integer) 0 127.0.0.1:6379> get letter "a" ``` # 把0100 0001(65)改为0110 0001(97)即把大写A改为了小写a getbit 获取二进制位上的值 getbit key offset # 获取二进制offset对应位的值 ### getbit示例 ``` 127.0.0.1:6379> set letter A OK 127.0.0.1:6379> getbit letter 0 (integer) 0 127.0.0.1:6379> getbit letter 1 (integer) 1 127.0.0.1:6379> getbit letter 7 (integer) 1 ``` bitop 对多个key逻辑操作 bitop operation destkey key1 [key2 ......] # 对key1 key2 keyN做operation,并把结果保存到destkey 上 # operation有AND、OR、NOT、XOR ### bitop示例 ``` 127.0.0.1:6379> setbit lower 2 1 (integer) 0 127.0.0.1:6379> setbit upper 2 0 (integer) 0 127.0.0.1:6379> set letter A OK 127.0.0.1:6379> bitop or letter letter lower (integer) 1 127.0.0.1:6379> get letter "a" ``` ## 哈希类型操作 散列类型采用了字典结构(k-v)进行存储。散列类型适合存储对象。可以采用这样的命名方式:对象类别和 ID 构成键名,使用字段表示对象的属性,而字段值则存储属性值。如:存储 ID 为 2 的汽车对象。 例如文章内容存储: 1. hset 设置哈希field域的值 hset key field value # 把key中 filed域的值设为value # 注:如果没有field域,直接添加,如果有,则覆盖原field域的值 ### hset示例 ``` 127.0.0.1:6379> hset user name zhangsan (integer) 1 127.0.0.1:6379> hset user age 25 (integer) 1 127.0.0.1:6379> hset user gender male (integer) 1 ``` 2. hmset 设置哈希多个field域的值 hmset key field1 value1 [field2 value2 field3 value3 ......fieldn valuen] # 一次设置多个field和对应的value ### hmset示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male OK ``` 3. hget 获取field域的值 hget key field # 获取field域的值 ###  hget示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male OK 127.0.0.1:6379> hget user age "26 ``` 4. hmget 获取多个field域的值 hget key field # 获取多个field域的值 ### hget示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male OK 127.0.0.1:6379> hmget user name age 1) "lisi" 2) "26" ``` 5. hgetall 获取所有field域和值 hgetall key # 获取哈希key的所有field域和值 ### hgetall示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male 127.0.0.1:6379> hgetall user 1) "name" 2) "lisi" 3) "age" 4) "26" 5) "gender" 6) "male" ``` 6. hlen 获取field的数量 hlen key # 获取field的数量 ### hlen示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male 127.0.0.1:6379> hlen user (integer) 3 ``` 7. hdel 删除field域 hdel key field # 删除key中 field域 ### hdel示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male 127.0.0.1:6379> hdel user age (integer) 1 127.0.0.1:6379> hgetall user 1) "name" 2) "lisi" 3) "gender" 4) "male" ``` 8. hexists 判断field域是否存在 hexists key field # 判断key中有没有field域 ### hexists示例 ``` 127.0.0.1:6379> hmset user name lisi age 26 gender male OK 127.0.0.1:6379> hexists user age (integer) 1 127.0.0.1:6379> hexists user height (integer) 0 ``` 9. hincrby 使field域的值加上整数 hincrby key field value # 使key中的field域的值加上整型值value ### hincrby示例 ``` 127.0.0.1:6379> hmset user name zhangsan height 158 OK 127.0.0.1:6379> hincrby user height 2 (integer) 160 ``` 10. hincrbyfloat 使field域的值加上浮点数 hincrbyfloat key field value # 使key中的field域的值加上浮点值value ### hincrbyfloat示例 ``` 127.0.0.1:6379> hmset user name zhangsan height 158 OK 127.0.0.1:6379> hincrbyfloat user height 5.5 "165.5" ``` 11. hkeys 获取所有所有field域的名字 hkeys key # 获取key中所有的field ### hkeys示例 ``` 127.0.0.1:6379> hmset user name zhangsan age 25 gender male OK 127.0.0.1:6379> hkeys user 1) "name" 2) "age" 3) "gender" ``` 12. kvals 获取所有所有field域的值 kvals key # 返回key中所有的value ### kvals示例 ``` 127.0.0.1:6379> hmset user name zhangsan age 25 gender male OK 127.0.0.1:6379> hvals user 1) "zhangsan" 2) "25" 3) "male" ``` ## 列表类型操作 列表类型(List) 列表类型(list)可以存储一个有序的字符串列表,常用的操作是向两端添加元素。 列表类型内部是使用双向链表实现的,也就是说,获取越接近两端的元素速度越快,代价是通过索引访问元素比较慢。 应用场景: (1)显示社交网站的新鲜事、热门评论和新闻等; (2)当队列使用; (3)记录日志。 lpush/rpush 在链表头/尾增加一个成员 lpush/rpush key value # 在链表头/尾增加一个成员,返回链表成员的个数 向列表的左边添加元素“1”,再依次加入“2”、“3” 在列表的右边依次加入两个元素“0”、“-1”: ### lpush/rpush示例实现 ``` 127.0.0.1:6379> lpush numbers 1 (integer) 1 127.0.0.1:6379> lpush numbers 2 3 (integer) 3 127.0.0.1:6379> rpush numbers 0 -1 (integer) 5 ``` lrange 获取链表成员 lrange key start stop # 返回链表中[start,stop]范围的成员 # 规律: 左数从0开始,右数从-1开始 ### lrange示例 ``` 127.0.0.1:6379> lrange letters 0 -1 1) "A" 2) "B" 3) "C" 4) "D" 127.0.0.1:6379> lrange letters 1 2 1) "B" 2) "C" ``` lpop/rpop 弹出链表中头/尾的成员 lpop/rpop key # 弹出链表中头/尾的成员 ### lpop/rpop示例 ``` 127.0.0.1:6379> lrange letters 0 -1 1) "A" 2) "B" 3) "C" 4) "D" 127.0.0.1:6379> lpop letters "A" 127.0.0.1:6379> rpop letters "D" 127.0.0.1:6379> lrange letters 0 -1 1) "B" 2) "C" ``` lrem 删除链表成员 lrem key count value # 从key链表中删除 value值 # 删除count的绝对值个value后结束 # count>0 从表头删除 # count<0 从表尾删除 ### lrem示例 ``` 127.0.0.1:6379> rpush letters A B C D A B C D A B C D (integer) 12 127.0.0.1:6379> lrem letters 2 A (integer) 2 127.0.0.1:6379> lrange letters 0 -1 1) "B" 2) "C" 3) "D" 4) "B" 5) "C" 6) "D" 7) "A" 8) "B" 9) "C" 10) "D" 127.0.0.1:6379> lrem letters -3 D (integer) 3 127.0.0.1:6379> lrange letters 0 -1 1) "B" 2) "C" 3) "B" 4) "C" 5) "A" 6) "B" 7) "C" ``` lindex 获取链表索引对应的值 lindex key index # 获取链表索引index对应的值 ### lindex示例 ``` 127.0.0.1:6379> rpush letters A B C D (integer) 4 127.0.0.1:6379> lindex letters 1 "B" 127.0.0.1:6379> lindex letters 2 "C" ``` llen key 获取链表成员个数 BASHllen key # 获取链表成员个数 ### llen示例 ``` 127.0.0.1:6379> rpush letters A B C D (integer) 4 127.0.0.1:6379> llen letters (integer) 4 ``` linsert 在链表中指定位置插入成员 linsert key after|before search value # 在key链表中寻找"search",并在search值之前|之后插入value # 如果没有找到,不插入值 # 如果找到一个search后,命令就结束了,因此不会插入多个value ### linsert示例 ``` 127.0.0.1:6379> rpush id 1 3 5 7 (integer) 4 127.0.0.1:6379> linsert id before 3 2 (integer) 5 127.0.0.1:6379> lrange id 0 -1 1) "1" 2) "2" 3) "3" 4) "5" 5) "7" 127.0.0.1:6379> linsert id after 5 6 (integer) 6 127.0.0.1:6379> lrange id 0 -1 1) "1" 2) "2" 3) "3" 4) "5" 5) "6" 6) "7" ``` blpop/brpop 一直等待弹出头/尾成员 blpop/brpop key timeout # 等待弹出key的头/尾成员 # Timeout为等待超时时间 # 如果timeout为0,则一直等待 # 应用s场景: 长轮询Ajax,在线聊天时,能够用到 ### blpop/brpop示例 ``` # 第一个终端操作: 127.0.0.1:6379> brpop chat 0 1) "chat" 2) "hello" (40.97s) # 第二个终端操作: 127.0.0.1:6379> rpush chat "hello" (integer) 1 ``` ## 无序集合操作 集合特性:无序性、唯一性、确定性 字符串的无序集合,不允许存在重复的成员。 多个集合类型之间可以进行并集、交集和差集运算。 图解交、并、差集: sadd 往集合添加成员 sadd key value1 value2 ... # 往集合key中增加成员 # 增加相同成员时只会添加一个(唯一性) ### sadd示例实现 ``` 127.0.0.1:6379> sadd letters a (integer) 1 127.0.0.1:6379> sadd letters a b c (integer) 2 127.0.0.1:6379> smembers letters 1)"c" 2)"b" 3)"a" 127.0.0.1:6379> sadd setA 1 3 5 7 (integer) 4 127.0.0.1:6379> sadd setB 2 3 4 5 (integer) 4 127.0.0.1:6379> sdiff setB setA 1)"2" 2)"4" 127.0.0.1:6379> sadd setA setB 1)"1" 2)"7" ``` srem 删除集合成员 srem key value1 value2 ... # 删除集合中为value1 value2...成员 # 返回真正删除掉的成员个数(不包括不存在的成员) ### srem示例 ``` 127.0.0.1:6379> sadd names zhangsan lisi wangwu (integer) 3 127.0.0.1:6379> srem names zhangsan lisi (integer) 2 127.0.0.1:6379> smembers names 1) "wangwu" ``` spop 随机删除集合一个成员 spop key # 随机删除集合key中的一个成员 # 应用场景:抽奖,抽中的人已经排除,不可能会被再次抽中了 ### spop示例 ``` 127.0.0.1:6379> sadd letters A B C D E F (integer) 6 127.0.0.1:6379> spop letters "A" 127.0.0.1:6379> spop letters "F" 127.0.0.1:6379> spop letters "B" 127.0.0.1:6379> spop letters "D" ``` srandmember 随机获取集合成员 srandmember key [count] # 随机获取集合key的count个成员,默认count是1 ### srandmember示例 ``` 127.0.0.1:6379> srandmember letters "C" 127.0.0.1:6379> srandmember letters 2 1) "E" 2) "B" 127.0.0.1:6379> srandmember letters 3 1) "D" 2) "C" 3) "E" ``` smembers 获取集合所有的成员 smembers key # 返回集合所有的成员 # 返回值的顺序不一定是添加成员的顺序(无序性) ### smembers示例 ``` 127.0.0.1:6379> sadd names zhangsan lisi wangwu (integer) 3 127.0.0.1:6379> smembers names 1) "lisi" 2) "wangwu" 3) "zhangsan" ``` sismember 判断成员是否存在集合中 sismember key value # 判断value是否存在集合key中,存在返回1,不存在返回0 ### sismember示例 ``` 127.0.0.1:6379> sadd names zhangsan lisi wangwu (integer) 3 127.0.0.1:6379> sismember names lisi (integer) 1 127.0.0.1:6379> sismember names zhaoliu (integer) 0 ``` scard 获取集合成员的个数 scard key # 获取集合成员的个数 ### scard示例 ``` 127.0.0.1:6379> sadd letters A B C D (integer) 4 127.0.0.1:6379> sadd letters E F (integer) 2 127.0.0.1:6379> scard letters (integer) 6 ``` smove 把一个集合中成员移动到另一个集合 smove value # 把集合source中的value删除,并添加到集合dest中 ### smove示例 ``` 127.0.0.1:6379> sadd letters A B C (integer) 3 127.0.0.1:6379> sadd num 1 2 3 (integer) 3 127.0.0.1:6379> smove letters num A (integer) 1 127.0.0.1:6379> smembers letters 1) "C" 2) "B" 127.0.0.1:6379> smembers num 1) "3" 2) "1" 3) "A" 4) "2" ``` sunion 获取多个集合的并集 sunion key1 key2 ... # 获取多个集合的并集 ### sunion示例 ``` 127.0.0.1:6379> sadd zhangsan A E G (integer) 3 127.0.0.1:6379> sadd lisi B E F (integer) 3 127.0.0.1:6379> sadd wangwu C D E (integer) 3 127.0.0.1:6379> sunion zhangsan lisi wangwu 1) "B" 2) "G" 3) "D" 4) "C" 5) "E" 6) "F" 7) "A" ``` sdiff 获取多个集合的差集 sdiff key1 key2 ... # 获取key1与key2...的差集 # 即key1-key2...(key1有其他集合没有的成员) ### sdiff示例 ``` 127.0.0.1:6379> sadd zhangsan A B C (integer) 3 127.0.0.1:6379> sadd lisi B D E (integer) 3 127.0.0.1:6379> sadd wangwu C E F (integer) 3 127.0.0.1:6379> sdiff zhangsan lisi wangwu 1) "A" ``` sinterstore 获取多个集合的交集并储存 sinterstore dest key1 key2 ... # 求出key1 key2 ...集合中的交集,并赋给dest ### sinterstor示例 ``` 127.0.0.1:6379> sadd zhangsan A C D (integer) 3 127.0.0.1:6379> sadd lisi B D E (integer) 3 127.0.0.1:6379> sadd wangwu D E G (integer) 3 127.0.0.1:6379> sinterstore class zhangsan lisi wangwu (integer) 1 127.0.0.1:6379> smembers class 1) "D" ``` ## 有序集合操作 在集合类型的基础上添加了排序的功能。 例如点击量排序 1. zadd 往有序集合添加成员 zadd key score1 key2 score2 key2 ... # 往有序集合key添加成员 ### zadd示例 ``` 127.0.0.1:6379> zadd ages 28 zhangsan 24 lisi 26 wangwu (integer) 0 127.0.0.1:6379> zrange ages 0 -1 1) "lisi" 2) "wangwu" 3) "zhangsan" ``` 2. zrange 按名次取成员 zrange key start stop [WITHSCORES] # 把集合排序后,返回名次[start,stop]的成员按名次取成员 # 默认是升续排列,withscores 是把score也打印出来 ### zrange示例 ``` 127.0.0.1:6379> zrange ages 0 -1 withscores 1) "lisi" 2) "24" 3) "wangwu" 4) "26" 5) "zhangsan" 6) "28" ``` 3. zrangebyscore 按分数取成员 zrangebyscore key min max [withscores] limit offset N # 集合(升序)排序后,取score在[min,max]内的成员,并跳过offset个,取出N个,按分数取成员 ### zrangebyscore示例 ``` 127.0.0.1:6379> zadd ages 28 zhangsan 24 lisi 26 wangwu (integer) 3 127.0.0.1:6379> zrangebyscore ages 25 30 1) "wangwu" 2) "zhangsan" 127.0.0.1:6379> zrangebyscore ages 25 30 limit 1 1 1) "zhangsan" ``` 4. zscore 获取指定成员的分数 ZSCORE key member # 获取指定成员的分数 ### zscore示例 ``` 127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu (integer) 3 127.0.0.1:6379> zscore height lisi "167" ``` 5. zcount 计算分数区间成员个数 zcount key min max # 计算[min,max]区间内成员的数量 ### zcount示例 ``` 127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu (integer) 3 127.0.0.1:6379> zcount height 170 180 (integer) 1 ``` 6. zrank/zrevrank 获取成员升序/降序的排名 zrank/zrevrank key member # 查询member的升序/降序排名,名次从0开始 ### zrank/zrevrank示例 ``` 127.0.0.1:6379> zadd ages 28 zhangsan 24 lisi 26 wangwu (integer) 0 127.0.0.1:6379> zrange ages 0 -1 1) "lisi" 2) "wangwu" 3) "zhangsan" 127.0.0.1:6379> zrank ages zhangsan (integer) 2 127.0.0.1:6379> zrevrank ages zhangsan (integer) 0 ``` 7. zrem 删除有序集合成员 zrem key value1 value2 .. # 删除集合中的成员 ### zre示例 ``` 127.0.0.1:6379> zrem ages wangwu (integer) 1 127.0.0.1:6379> zrange ages 0 -1 1) "lisi" 2) "zhangsan" ``` 8. zremrangebyrank 按排名删除成员 zremrangebyrank key start end # 按排名删除成员,删除名次在[start,end]之间的 ### zremrangebyrank示例 ``` 127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu 178 zhaoliu (integer) 1 127.0.0.1:6379> zremrangebyrank height 0 1 (integer) 2 127.0.0.1:6379> zrange height 0 -1 1) "zhaoliu" 2) "wangwu" ``` 9. zremrangebyscore 按分数删除成员 zremrangebyscore key min max # 按照socre来删除成员,删除score在[min,max]之间的 ### zremrangebyscore示例 ``` 127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu 178 zhaoliu (integer) 2 127.0.0.1:6379> zremrangebyscore height 170 180 (integer) 2 127.0.0.1:6379> zrange height 0 -1 1) "lisi" 2) "wangwu" ``` 10. zinterstore 求交集再计算 zinterstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] # 求key1、key2...的交集,key1、key2...的权重分别是 weight1、weight2... # 聚合方法用: sum|min|max # 聚合的结果保存在destination集合内 ### zinterstore示例 ``` 127.0.0.1:6379> zadd zhangsan 5 iphone6s 7 galaxyS7 6 huaweiP9 (integer) 3 127.0.0.1:6379> zadd lisi 3 iphone6s 9 galaxyS7 4 huaweiP9 2 HTC10 (integer) 4 127.0.0.1:6379> zinterstore result 2 zhangsan lisi (integer) 3 127.0.0.1:6379> zrange result 0 -1 withscores 1) "iphone6s" 2) "8" 3) "huaweiP9" 4) "10" 5) "galaxyS7" 6) "16" 127.0.0.1:6379> zinterstore result 2 zhangsan lisi aggregate max (integer) 3 127.0.0.1:6379> zrange result 0 -1 withscores 1) "iphone6s" 2) "5" 3) "huaweiP9" 4) "6" 5) "galaxyS7" 6) "9" ``` 11. zunionstore 求并集再计算 zunionstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] # 求key1、key2...的并集,key1、key2...的权重分别是 weight1、weight2... # 聚合方法用: sum|min|max # 聚合的结果保存在destination集合内 ### zunionstore示例 ``` 127.0.0.1:6379> zadd zhangsan 4 iphone6s 6 huaweiP9 8 xiaomi5 (integer) 3 127.0.0.1:6379> zadd lisi 2 iphone6s 8 galaxS7 5 meizu6 (integer) 3 127.0.0.1:6379> zunionstore result 2 zhangsan lisi (integer) 5 127.0.0.1:6379> zrange result 0 -1 withscores 1) "meizu6" 2) "5" 3) "huaweiP9" 4) "6" 5) "iphone6s" 6) "6" 7) "galaxS7" 8) "8" 9) "xiaomi5" 10) "8" 127.0.0.1:6379> zunionstore result 2 zhangsan lisi aggregate max (integer) 5 127.0.0.1:6379> zrange result 0 -1 withscores 1) "iphone6s" 2) "4" 3) "meizu6" 4) "5" 5) "huaweiP9" 6) "6" 7) "galaxS7" 8) "8" 9) "xiaomi5" 10) "8" ``` ## java操作Redis数据库 ## Redis系统管理 # 教材及素材获取 https://www.ossbar.com/#/productDetail?proData=%7B%22productId%22%3A315,%22skuId%22%3A972,%22shopId%22%3A138%7D