在本章中,介绍了什么是Redis以及NoSQL,NoSQL与MySQL的差异,Redis的数据结构以及基本数据类型,Redis的通用命令,以及redis客户端下的五项常用数据类型的命令。
一、什么是Redis
1.1、Redis简介
Redis诞生于2009年全称是Remote Dictionary Server 远程词典服务器,是一个基于内存的键值型NoSQL数据库。
特征:
-
键值(key-value)型,value支持多种不同数据结构,功能丰富
-
单线程,每个命令具备原子性
-
低延迟,速度快(基于内存.IO多路复用.良好的编码)。
-
支持数据持久化
-
支持主从集群.分片集群
-
支持多语言客户端
Redis是一种键值型的NoSQL数据库,这里有两个关键字:键值型 NoSQL
- 键值型:是指Redis中存储的数据都是以key.value对的形式存储,而value的形式多种多样,可以是字符串.数值.甚至json
- NoSql:也叫非关系型数据库,对于存储的数据,没有类似MySQL那么严格的约束,比如唯一性,是否可以为null等等,所以我们把这种松散结构的数据库,称之为NoSQL数据库。
1.2、认识NoSQL与MySQL之间的差异
- NoSql:可以翻译做Not Only Sql(不仅仅是SQL),或者是No Sql(非Sql的)数据库。是相对于传统关系型数据库而言,有很大差异的一种特殊的数据库,因此也称之为非关系型数据库。
- 结构化与非结构化 :
传统关系型数据库是结构化数据,每一张表都有严格的约束信息:字段名.字段数据类型.字段约束等等信息,插入的数据必须遵守这些约束。
而NoSql则对数据库格式没有严格约束,往往形式松散,自由。可以是键值型,也可以是文档型,甚至可以是图格式。 - 关联和非关联:传统数据库的表与表之间往往存在关联,例如外键,而非关系型数据库不存在关联关系,要维护关系要么靠代码中的业务逻辑,要么靠数据之间的耦合。
- 查询差异:传统关系型数据库会基于Sql语句做查询,语法有统一标准,而不同的非关系数据库查询语法差异极大,五花八门各种各样。
- 事务:传统关系型数据库能满足事务ACID的原则,而非关系型数据库往往不支持事务,或者不能严格保证ACID的特性,只能实现基本的一致性。
- 存储方式:
关系型数据库基于磁盘进行存储,会有大量的磁盘IO,对性能有一定影响。
非关系型数据库,他们的操作更多的是依赖于内存来操作,内存的读写速度会非常快,性能自然会好一些。 - 扩展方式:
关系型数据库集群模式一般是主从,主从数据一致,起到数据备份的作用,称为垂直扩展。
非关系型数据库可以将数据拆分,存储在不同机器上,可以保存海量数据,解决内存大小有限的问题。称为水平扩展。
二、Redis的数据结构
Redis是一个key-value的数据库,key一般是String类型,但是value的类型多种多样,我们经常能用到的就是上面五种基本数据类型。
1. String类型:也就是字符串类型,是Redis中最简单的存储类型。其value是字符串,不过根据字符串的格式不同,又可以分为3类:
-
string:普通字符串
-
int:整数类型,可以做自增.自减操作
-
float:浮点类型,可以做自增.自减操作
2. Hash类型:也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:
Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD:
3. List:Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。特征也与LinkedList类似:
-
有序
-
元素可以重复
-
插入和删除快
-
查询速度一般
4.Set:Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:
-
无序
-
元素不可重复
-
查找快
-
支持交集.并集.差集等功能
5.SortedSet:Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
SortedSet具备下列特性:
-
可排序
-
元素不重复
-
查询速度快
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
三、客户端下常用Redis基本命令
特别说明:命令不要死记,Redis中的查询不同于SQL,他在不同的客户端下可能有不同的查询方式,所以初学者在不大量运用到Redis之前靠死记硬背是很难掌握的,所以我们要知道不同数据结构能干什么就好,而不是死记硬背命令。
本章为客户端下的Redis常用命令,与IDE中也许会有出入!
3.1、Key的层级结构
Redis没有类似MySQL中的Table的概念,我们该如何区分不同类型的key呢?
例如,需要存储用户.商品信息到redis,有一个用户id是1,有一个商品id恰好也是1,此时如果使用id作为key,那就会冲突了,该怎么办?
我们可以通过给key添加前缀加以区分,不过这个前缀不是随便加的,有一定的规范:
Redis的key允许有多个单词形成层级结构,多个单词之间用':'隔开,格式如下:项目名:业务名:id
这个格式并非固定,也可以根据自己的需求来删除或添加词条。
3.2、通用命令
通用指令是大部分数据类型的都可以使用的指令,常见的有:(可以记住在Reis中都有哪些功能,具体的指令可以之后查)
-
KEYS:查看符合模板的所有key
-
DEL:删除一个指定的key
-
EXISTS:判断key是否存在
-
EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除
-
TTL:查看一个KEY的剩余有效期
127.0.0.1:6379> keys * #查询所有
1) "name"
2) "age"
127.0.0.1:6379> keys a* #查询以a开头的key
1) "age"
127.0.0.1:6379> del name #删除单个
(integer) 1 #成功删除1个
127.0.0.1:6379> exists age #是否存在key为nage
(integer) 1
127.0.0.1:6379> exists name #是否存在key为name(刚刚删了)
(integer) 0
127.0.0.1:6379> expire age 10 #设置过期时间
(integer) 1
127.0.0.1:6379> ttl age #返回秒数
(integer) 8
3.3、String命令
String的常见命令有:
以下命令除了 INCRBYFLOAT 都是常用命令
-
SET:添加或者修改已经存在的一个String类型的键值对
-
GET:根据key获取String类型的value
-
SET和GET补充说明: 如果key不存在则是新增,如果存在则是修改
-
127.0.0.1:6379> set name Rose //原来不存在 OK 127.0.0.1:6379> get name "Rose" 127.0.0.1:6379> set name Jack //原来存在,就是修改 OK 127.0.0.1:6379> get name "Jack"
-
-
MSET:批量添加多个String类型的键值对
-
MGET:根据多个key获取多个String类型的value
-
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> MGET name age k1 k2 k3 1) "Jack" //之前存在的name 2) "10" //之前存在的age 3) "v1" 4) "v2" 5) "v3"
-
-
INCR:让一个整型的key自增1
-
INCRBY:让一个整型的key自增并指定步长,例如:incrby num 2 让num值自增2
-
127.0.0.1:6379> get age "10" 127.0.0.1:6379> incr age //增加1 (integer) 11 127.0.0.1:6379> get age //获得age "11" 127.0.0.1:6379> incrby age 2 //一次增加2 (integer) 13 //返回目前的age的值 127.0.0.1:6379> incrby age 2 (integer) 15 127.0.0.1:6379> incrby age -1 //也可以增加负数,相当于减 (integer) 14 127.0.0.1:6379> incrby age -2 //一次减少2个 (integer) 12 127.0.0.1:6379> DECR age //相当于 incr 负数,减少正常用法 (integer) 11 127.0.0.1:6379> get age "11"
-
-
INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
-
SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
-
127.0.0.1:6379> set name Jack //设置名称 OK 127.0.0.1:6379> setnx name lisi //如果key不存在,则添加成功 (integer) 0 127.0.0.1:6379> get name //由于name已经存在,所以lisi的操作失败 "Jack" 127.0.0.1:6379> setnx name2 lisi //name2 不存在,所以操作成功 (integer) 1
-
-
SETEX:添加一个String类型的键值对,并且指定有效期
-
127.0.0.1:6379> setex name 10 jack OK 127.0.0.1:6379> ttl name (integer) 8
-
3.4、Hash命令
hash中会有最大的KET以及Value,Value中也会有相当于key-value的结构,此时是小key叫field。
-
HSET key field value:添加或者修改hash类型key的field的值
-
HGET key field:获取一个hash类型key的field的值
-
127.0.0.1:6379> HSET user:3 name Lucy//大key是 user:3 小key是name,小value是Lucy (integer) 1 127.0.0.1:6379> HSET user:3 age 21// 如果操作不存在的数据,则是新增 (integer) 1 127.0.0.1:6379> HSET user:3 age 17 //如果操作存在的数据,则是修改 (integer) 0 127.0.0.1:6379> HGET user:3 name "Lucy" 127.0.0.1:6379> HGET user:3 age "17"
-
-
HMSET:批量添加多个hash类型key的field的值
-
HMGET:批量获取多个hash类型key的field的值
-
127.0.0.1:6379> HMSET user:4 name LiLei age 20 sex man OK 127.0.0.1:6379> HMGET user:4 name age sex 1) "LiLei" 2) "20" 3) "man"
-
-
HGETALL:获取一个hash类型的key中的所有的field和value
-
127.0.0.1:6379> HGETALL user:4 1) "name" 2) "LiLei" 3) "age" 4) "20" 5) "sex" 6) "man"
-
-
HKEYS、HVALS :获取一个hash类型的key中的所有的field,value
-
127.0.0.1:6379> HKEYS user:4 1) "name" 2) "age" 3) "sex" 127.0.0.1:6379> HVALS user:4 1) "LiLei" 2) "20" 3) "man"
-
-
HINCRBY:让一个hash类型key的字段值自增并指定步长
-
127.0.0.1:6379> HINCRBY user:4 age 2 (integer) 22 127.0.0.1:6379> HVALS user:4 1) "LiLei" 2) "22" 3) "man" 127.0.0.1:6379> HINCRBY user:4 age -2 (integer) 20
-
-
HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
3.5、List命令
-
LPUSH key element ... :向列表左侧插入一个或多个元素
-
RPUSH key element ... :向列表右侧插入一个或多个元素
-
127.0.0.1:6379> LPUSH users 1 2 3 (integer) 3 127.0.0.1:6379> RPUSH users 4 5 6 (integer) 6 # 现在内存中结构应为 3 2 1 4 5 6
-
-
LPOP key:移除并返回列表左侧的第一个元素,没有则返回null
-
RPOP key:移除并返回列表右侧的第一个元素
-
127.0.0.1:6379> LPOP users "3" 127.0.0.1:6379> RPOP users "6" # 现在内存中结构应为 2 1 4 5
-
-
LRANGE key star end:返回一段角标范围内的所有元素
-
127.0.0.1:6379> LRANGE users 1 2 1) "1" 2) "4"
-
-
BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回null
3.6、Set命令
-
SADD key member ... :向set中添加一个或多个元素
-
SMEMBERS:获取set中的所有元素
-
127.0.0.1:6379> sadd s1 a b c (integer) 3 127.0.0.1:6379> smembers s1 1) "c" 2) "b" 3) "a"
-
-
SREM key member ... : 移除set中的指定元素
-
SISMEMBER key member:判断一个元素是否存在于set中
- SCARD key: 返回set中元素的个数
-
127.0.0.1:6379> srem s1 a (integer) 1 127.0.0.1:6379> SISMEMBER s1 a (integer) 0 127.0.0.1:6379> SISMEMBER s1 b (integer) 1 127.0.0.1:6379> SCARD s1 (integer) 2
-
-
下面是交集差集并集,很重要
-
SINTER key1 key2 ... :求key1与key2的交集
-
SDIFF key1 key2 ... :求key1与key2的差集
-
SUNION key1 key2 ..:求key1和key2的并集
-
-
看案例
案例
-
将下列数据用Redis的Set集合来存储:
-
张三的好友有:李四.王五.赵六
-
李四的好友有:王五.麻子.二狗
-
利用Set的命令实现下列功能:
-
计算张三的好友有几人
-
计算张三和李四有哪些共同好友
-
查询哪些人是张三的好友却不是李四的好友
-
查询张三和李四的好友总共有哪些人
-
判断李四是否是张三的好友
-
判断张三是否是李四的好友
-
将李四从张三的好友列表中移除
127.0.0.1:6379> SADD zs lisi wangwu zhaoliu
(integer) 3
127.0.0.1:6379> SADD ls wangwu mazi ergou
(integer) 3
127.0.0.1:6379> SCARD zs
(integer) 3
127.0.0.1:6379> SINTER zs ls
1) "wangwu"
127.0.0.1:6379> SDIFF zs ls
1) "zhaoliu"
2) "lisi"
127.0.0.1:6379> SUNION zs ls
1) "wangwu"
2) "zhaoliu"
3) "lisi"
4) "mazi"
5) "ergou"
127.0.0.1:6379> SISMEMBER zs lisi
(integer) 1
127.0.0.1:6379> SISMEMBER ls zhangsan
(integer) 0
127.0.0.1:6379> SREM zs lisi
(integer) 1
127.0.0.1:6379> SMEMBERS zs
1) "zhaoliu"
2) "wangwu"
3.7、SortedSet类型
SortedSet与Set大差不大,在开发中也没有上述四种常用,了解其有什么功能即可,注意他有set没有的去重排序功能。
-
ZADD key score member:添加一个或多个元素到sorted set ,如果已经存在则更新其score值
-
ZREM key member:删除sorted set中的一个指定元素
-
ZSCORE key member : 获取sorted set中的指定元素的score值
-
ZRANK key member:获取sorted set 中的指定元素的排名
-
ZCARD key:获取sorted set中的元素个数
-
ZCOUNT key min max:统计score值在给定范围内的所有元素的个数
-
ZINCRBY key increment member:让sorted set中的指定元素自增,步长为指定的increment值
-
ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
-
ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
-
ZDIFF、ZINTER、ZUNION:求差集.交集.并集
注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可,例如:
-
升序获取sorted set 中的指定元素的排名:ZRANK key member
-
降序获取sorted set 中的指定元素的排名:ZREVRANK key memeber