Redis--Redis命令详解
数据结构介绍
Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样:
类型 | 示例 |
---|---|
String | hello world |
Hash | {name:"jack",age:21} |
List | [A-> B -> C -> C] |
Set | {A,B,C} |
SortedSet | {A:1,B:2,C:3} |
GEO(地理坐标(经纬度)) | {A:(120.3,30.5)} |
BitMap(按位) | 011001010001010011 |
HyperLog(按位) | 1001010101010011 |
常用的类型为前五个,后三个则为特殊类型。
Redis为了方便我们学习,将操作不同数据类型的命令也做了分组,在官网(Commands | Docs)可以查看到不同的命令:
Redis通用命令
通用命令是部分数据类型的,都可以使用的指令,可以查阅官方文档Commands | Docs
我们将常用的命令整理如下:
-
keys:查看符合模板的所有key
可以通过 help [command] 可以查看一个命令的具体用法
也可以通过查询官方文档
案例展示:
keys命令行基于通配符去匹配(模糊查询),效率一定不高,当redis的数据量达到一定规模时,数百上千万时,模糊查询往往会给服务器带来巨大的负担,keys的搜索会搜索很长一段时间,又因为redis是单线程,在其搜索的这一段时间内是无法去完成其他业务的,等于整个redis服务被阻塞了。不建议在生产环境设备下使用。
如果Redis数据库为集群模式,有主有从,就可以在从节点上使用keys命令行,但不要在主节点上使用,会导致主节点阻塞
-
DEL:删除指定的key
案例展示:
可以删除一个或多个key,如果想删除的key不存在也不会报错,只会将存在的key删除,并返回一个Integer类型的值(删除key的个数)
-
exists:判断key是否存在
案例展示:
检测指定的key是否存在,如果存在则返回1,不存在则返回0
-
expire:给一个key设置有效期,有效期到期时key会被自动删除
为什么要存在这样的一个指令呢?
因为redis是基于内存存储的,我们将大量数据保存在内存之中,如果一直插入而不去删除,最终只会将内存占满,为了解决这个问题,redis官方提供了这一方法。
我们可以通过expire指令来给key设置有效期,根据业务要求决定是否自动删除,比如,在短信验证码的业务代码中,它的存在时间一般在五分钟,我们就可以设置5分钟有效期,五分钟后删除,这样也可以节省内存空间。
-
TTL:查看一个key的剩余有效期,与expire配合使用
案例展示:
在TTL指令中:-2代表key已经被删除,-1代表key的永久存在,其余数字代表该key的有效期。
String类型
众所周知:redis数据库是键值对数据库,只不过value的类型多种多样
而String类型也就是字符串类型,是Redis中最简单的存储类型
其value是字符串,不过根据字符串的格式不同,又可以分为3类:
-
String:普通字符串
-
int:整数类型,可以做自增、自减操作
-
float:浮点类型,可以做自增、自减操作
案例展示:
key | value |
---|---|
msg | hello world |
num | 10 |
score | 92.5 |
不管是哪种格式,底层都是字节数组形式存储,为了节省空间,数值类型的字符串编码方式不同,将数字直接转为二进制的形式去存储,这样一来,一个字节可以表示很大的数字。
而字符串只能将字符转换为字节码,然后再去存储,相对而言占用空间更大。
因此字符串表现形式不一样,编码方式不一样,但本质都是数组。
可以做到将图片编译成字节存在String类型中(不建议)。
但字符串类型的最大空间不能够超过512m(兆)。
String类型的常见命令
基本增查:
-
set:添加或者修改已经存在的一个String类型的键值对
-
get:根据key获取String类型的value
-
mset:批量添加多个String类型的键值对
-
mget:根据多个key获取多个String类型的value,返回值为多个value组成的数组
综合案例:
数值类型的自增
-
INCR:让一个整形的key自增1
-
INCRBY:让一个整形的key自增并指定步长,例如:incrby num 2 让num值自增2(也可以自减,后面数值为负数,或者使用decrby指令 )
综合案例:
-
INCRBYFLOAT:让一个浮点类型的key自增并指定步长,没有默认步长,只能指定
案例展示:
组合指令
-
SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
案例展示:
-
SETEX:添加一个String类型的键值对,并指定有效期。
案例展示
key的层级格式
问题引入:
在Redis数据库中,key具有唯一性,所以我们大多数情况下会以数据的id作为key,形成唯一标识。
但是Redis没有类似MySQL中的table的概念,如何区分不同类型的key成了难题。
假如需要存储客户、商品信息到redis中,有一个客户的id是1,有一个商品ID也是1,ID相同 如何分辨?
这时可能会想可以在id上拼接一些字符串,由此引出:key的结构
key的结构
Redis的key允许多个单词形成层级结构,多个单词之间用' :'隔开,格式如下:
项目名:业务名:类型:id
这个格式并非固定,也可以根据自己的需求来删除或添加词条。
假如项目名为lyc 有user和product两种不同类型的数据,我们可以这样定义key:
-
user相关的key:
lyc:user:id:1
-
product相关的key:
lyc:product:1
在项目中,无论是user还是product,都是Java对象,我们该怎样将其传入到value的位置。
在学习String类型时,value可以是字符串,而Java对象可以通过序列化成json的风格
例如:一个User对象,将其序列化为json字符串后存储:
key | value |
---|---|
lyc:user:1 | {"id":1,"name":"Jack","age"" 21} |
lyc:product:1 | {"id" :1 , "name": "华为" "price": 5999} |
案例展示:
从图形界面上可以更加直观:
Hash类型
hash类型,也叫散列,其value是一个无序字典,类似于Java的HashMap结构。
String结构是将Java对象序列化成JSON字符串后存储,当需要改变对象某个字段很不方便,因为无论对象中的字段有多少,在String类型的value只是一个字符串,想要修改某个字段就只能修改整个字符串。
key | value |
---|---|
lyc:user:1 | {"id":1,"name":"Jack","age"" 21} |
lyc:product:1 | {"id" :1 , "name": "华为" "price": 5999} |
而hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CURD:
key | value | |
fileld | value | |
lyc:user:1 | name | jack |
age | 21 | |
lyc:user:2 | name | Rose |
age | 18 |
Hash类型的常见命令
-
hset key filed value:添加或者修改Hash类型key的field的值
可以将对象中的每个字段独立存储,可以针对单个字段做修改
-
hget key field:获取一个Hash类型key的field的值
-
hmset:批量添加多个Hash类型key的field的值
-
hmget:批量获取多个Hash类型key的field的值
综合案例:
-
hgetall:获取一个Hash类型的key中的所有filed和value
-
hkeys:获取一个hash类型的key中的所有的field
-
hvals:获取一个hash类型的key中的所有的value
综合案例:
-
hincrby: 让一个hash类型key的字段值自增并指定步长
-
hsetnx:添加一个Hash类型的key的field值,前提是这个field不存在,否则不执行
若存在该field值,则返回值为0,表示不执行,若返回值为1,表示执行成功。
List类型
不同数据类型的差异主要是值的数据结构不同
Redis中的List类型与Java的LinkedList类似,可以看做一个双向链表结构,即可以支持正向检索,也可以支持反向检索
特征也与LinkedList相似:
-
有序
-
可重复
-
插入与删除快
-
查询速度一般
主要用于一些对数据顺序有要求的场景下(常用于存储一个有序数据):比如评论区的评论,是要区分谁先谁后,这些数据都可以使用list类型保存。
List常见命令
-
lpush key element...: 向列表左侧插入一个或多个元素
-
lpop key: 移除并返回列表左侧的第一个元素,没有则返回nil
-
rpush key element...:向列表右侧插入一个或多个元素
-
rpop key:移除并返回列表右侧的第一个元素,没有则返回nil
原理图示:
-
lrange key star end :返回一段角标氛围内的所有元素
-
blpop 和 brpop:与Lpop 和 rpop类似,只不过在没有元素时等待指定时间,而不是直接返回nil(b-> block 阻塞)
综合案例:
思考:
-
如何利用List结构模拟一个栈
栈:先进后出,就如同子弹射击情况一致,先压进去的子弹最后发射
入口与出口在同一边
我们就可以使用同一边的push与pop,如lpush ,lpop 或rpus rpop
-
如何利用List结构模拟一个队列
队列:先进先出,例如排队,抢票等
入口和出口不在同一边.
我们可以使用不同边的push与pop 如 lpush rpop 或 rpush lpop
-
如何利用List结构模拟一个阻塞队列
入口和出口不在同一边 且使用 blpop或brpop
Set类型
Redis的set结构与Java中的HashSet类似,可以看成一个value为null的HashMap。因为也是一个Hash表,因此具备和HashSet类似的特征:
-
无序:每一个插入的元素都会用哈希算法计算插入的角标
-
不重复
-
查找快
-
支持交集、并集、差集等功能
set类型的常见命令:
-
sadd key member ...: 向set中添加了一个或多个元素
-
srem key member... :移除set中的指定元素
-
scard key: 返回set中元素的个数
-
sismember key member : 判断一个元素是否存在于set中
-
smembers:获得set的所有元素
综合案例:
这些命令是对单个集合的增删改查的操作
以下命令是针对于多个集合之间的一些交互操作
-
sinter key1 key2...: 求key1与key2的交集
-
sdiff key1 key2...:求key1与key2的差集
-
sunion key1 key2...:求key1与key2的并集
案例展示:
将下列数据用Redis的Set集合来存储:
-
张三的好友有:李四、王五、
-
赵六李四的好友有:王五、麻子、二狗
利用Set的命令实现下列功能:
-
计算张三的好友有几人
-
计算张三和李四有哪些共同好友
-
查询哪些人是张三的好友却不是李四的好友
-
查询张三和李四的好友总共有哪些人
-
判断李四是否是张三的好友
-
判断张三是否是李四的好友
-
将李四从张三的好友列表中移除
代码展示:
SortedSet类型
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构差别很大,SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素进行排序,底层的实现是一个跳表(SkipList)加Hash表。
SortedSet具有以下特性:
-
可排序
-
元素不重复
-
查询速度快
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
SortedSet的常见命令:
-
zadd key score member :添加一个或多个元素到SortedSet,如果已经存在则更新score值
-
arem key member: 删除SortedSet中的一个指定元素
-
zscore key member: 获取SortedSet中指定的元素的score值
-
zrank key member: 获取SortedSet 中指定元素的排名
-
zcard key: 获取SortedSet中的元素个数
-
zcount key min max: 统计score值在给定范围内的所有元素个数
-
zincrby key increment member: 让SortedSet 中的元素自增,步长为指定的increment值
-
zrange key min max: 按照score排序后,获取指定排名范围内的元素
-
zrangebyscore key min max: 按照score排序后,获取指定score范围内的元素
-
zdiff,zinter,zunion :求差集、交集、并集。
注意事项:所有的排名默认都是升序,如果要则在命令的Z后面加上REV即可(反转)
案例展示:
将班级的下列同学得分存入redis的SortedSet中:
Jack 85, Lucy 89, Rose 82, Tom 95, Jerry 78,Amy 92,Miles 76
-
实现下列要求
-
删除Tom
-
获取Amy的分数
-
获取Rose的排名
-
查询80分以下的学生
-
给Amy同学加2分
-
查出成绩前三名的同学
-
差出成绩80分以下的所有同学
代码展示:
以上就是SortedSet常用命令的使用方式
希望对大家有所帮助