Redis是典型的key-value数据库,key一般是字符串,而value包含很多不同的数据类型,以下是常见的八种数据类型:
上图中的前五种是最常见的数据类型,因而称之为redis的基本类型,而后三种数据类型是建立在前五种数据类型之上的,这些数据类型一般用于解决特定场景的业务需求,使用频率比前五种要低,因此也称为特殊类型
除了以上八种数据类型以外,redis还包括很多种其他的数据类型,用来实现各种各样特殊的功能需求
由于不同数据类型的命令之间存在差异,Redis官方为了方便我们学习,特意将操作不同数据类型的命令做了分组,我们可以在官网( https://redis.io/commands )可以查看到不同数据类型的命令:
假如我们现在要查看String类型相关的命令:
不同类型的命令称为一个group,我们也可以在redis-cli中通过help命令来查看各种不同group的命令,具体语法为:
help @数据类型
接下来,我们就学习常见的五种基本数据类型的相关命令。
String类型,也就是字符串类型,是Redis中最简单的存储类型。其value是字符串,不过根据字符串的格式不同,又可以分为3类:
不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m.
String的常见命令有:
指令 | 作用 | 语法 | 备注 |
---|---|---|---|
SET | 添加或者修改已经存在的一个String类型的键值对 | set key value | 键存在则修改,键不存在则添加 |
GET | 根据key获取String类型的value | get key | |
MSET | 批量添加多个String类型的键值对 | set key1 value1 [key2 value2…] | |
MGET | 根据多个key获取多个String类型的value | get key1 [key2…] | |
INCR | 让一个整型的key自增1 | incr key | |
INCRBY | 让一个整型的key自增并指定步长,例如:incrby num 2 让num值自增2 | incrby key num | 指定的num为负数代表自减 |
INCRBYFLOAT | 让一个浮点类型的数字自增并指定步长 | incrbyfloat key num | 指定的num为负数代表自减 |
SETNX | 添加一个String类型的键值对,前提是这个key不存在,否则不执行 | setnx key value | set key value nx 可以实现同样的效果 |
SETEX | 添加一个String类型的键值对,并且指定有效期(单位:秒) | setex key seconds value | set key value ex seconds 可以实现同样的效果 |
APPEND | 在指定key的value后添加内容 | append key value | 返回值为添加后value的长度,如果key不存在则创建一个 |
STRLEN | 获取指定key的value长度 | strlen key | |
GETRANGE | 获取value指定索引范围内的字符串 | getrange key start end | 索引从零开始,左右闭区间 |
当我们拿到一个redis命令不知道怎么使用时,可以通过help [command] 可以查看其具体用法,例如:
String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时,必须将整个字符串获取并反序列化成对象才能进行修改,十分不方便:
针对上述情况,我们就可以使用Hash类型来存储数据,Hash类型也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。
Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD:
Hash的常见命令有:
指令 | 作用 | 语法 | 备注 |
---|---|---|---|
HSET | 添加或者修改hash类型key的field的值 | hset key field value [field value…] | 可以一次添加多个field的值,如果field已存在则修改该field的值 |
HGET | 获取一个hash类型key的field的值 | hget key field | |
HMSET | 批量添加一个hash类型key的多个field的值 | hmset key field value [field value…] | 效果同于hset |
HMGET | 批量获取一个hash类型key的多个field的值 | hmget key field [field…] | |
HGETALL | 获取一个hash类型key中的所有的field以及其值 | hgetall key | |
HKEYS | 获取一个hash类型key中的所有的field | hkeys key | |
HVALS | 获取一个hash类型key中的所有的field的值 | hvals key | |
HINCRBY | 让一个hash类型key的字段值自增并指定步长 | hincrby key field num | 指定的num如果为负数则自减 |
HSETNX | 添加一个hash类型key的field值,前提是这个field不存在,否则不执行 | hsetnx key field value |
在使用HSET、HMSET或HSETNX时添加一个field的值时,还会去判断当前Hash类型key中是否存在该field,如果不存在则在当前Hash类型key中添加该field,因此Hash类型key的field是不固定的,每一条Hash类型key都可能有完全不相同的field
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。其特征也与LinkedList类似:
List类型常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。List的常见命令有:
指令 | 作用 | 语法 | 备注 |
---|---|---|---|
LPUSH | 向列表左侧插入一个或多个元素 | lpush key element [element…] | 插入多个元素时,后插入的元素会在先插入的元素左侧 |
LPOP | 移除并返回列表左侧的任意数量元素 | lpop key count | 返回的元素会被移除 |
RPUSH | 向列表右侧插入一个或多个元素 | rpush key element [element…] | 插入多个元素时,后插入的元素会在先插入的元素右侧 |
RPOP | 移除并返回列表右侧的任意数量元素 | rpop key count | 返回的元素会被移除 |
LRANGE | 返回一段角标范围内的所有元素 | lrange key star end | 从列表左侧开始获取,角标从零开始,左右闭区间。lrange key 0 -1 表示返回当前列表所有元素 |
BLPOP/BRPOP | 与LPOP和RPOP类似,但是在获取元素时会指定等待时间,如果列表中没有元素会先等待,而不是直接返回null | blpop key [key …] timeout | |
LINDEX | 通过索引获取列表中的元素。 | lindex key index | 可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 |
LLEN | 获取列表长度 | llen key | |
LREM | 删除 count 个元素值为 value 的元素 | lrem key count value | 返回值为成功删除的元素的个数 |
LSET | 修改指定索引的元素值 | lset key index value | 索引从0开始 |
Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:
无序
元素不可重复
查找快
支持交集、并集、差集等功能
Set的常见命令有:
命令 | 作用 | 语法 | 备注 |
---|---|---|---|
SADD | 向set中添加一个或多个元素 | sadd key member [member…] | |
SREM | 移除set中的指定元素 | srem key member [member…] | |
SCARD | 返回set中元素的个数 | scard key | |
SISMEMBER | 判断一个元素是否存在于set中 | sismember key member | 存在则返回1,不存在则返回0 |
SMEMBERS | 获取set中的所有元素 | smembers key | |
SINTER | 返回指定key之间的交集 | sinter key1 key2 [key3…] | |
SDIFF | 返回指定key之间的差集 | sdiff key1 key2 [key3…] | 差集结果会受到指令中key顺序的影响,例如sdiff key1 key2 获取的就是key1中存在但key2中不存在的元素 |
SUNION | 返回指定key之间的并集 | sunion key1 key2 [key3…] | |
SPOP | 随机弹出指定数量的元素 | SPOP key [count] | 不指定count则弹出一个 |
SRANDMEMBER | 随机返回指定数量的元素 | srandmember key [count] | 不指定count则返回一个 |
SMOVE | 将一个set中的指定元素移动到另一个set中 | smove key1 key2 member |
练习:
- 将下列数据用Redis的Set集合来存储:
- 利用Set的命令实现下列功能:
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
SortedSet具备下列特性:
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
SortedSet的常见命令有:
命令 | 作用 | 语法 | 备注 |
---|---|---|---|
ZADD | 添加一个或多个元素到sorted set ,如果已经存在则更新其score值 | zadd key score member [score member…] | |
ZREM | 删除sorted set中的一个或多个指定元素 | zrem key member [member] | |
ZSCORE | 获取sorted set中的指定元素的score值 | zscore key member | |
ZRANK | 获取sorted set 中的指定元素的排名 | zrank key member | 排名从零开始,升序 |
ZCARD | 获取sorted set中的元素个数 | zcard key | |
ZCOUNT | 统计score值在给定范围内的所有元素的个数 | zcount key min max | 左右闭区间 |
ZINCRBY | 让sorted set中的指定元素自增,步长为指定的increment值 | zincrby key increment member | 注意member一定要打上双引号 |
ZRANGE | 按照score排序后,获取指定排名范围内的元素 | zrange key min max | 排名从零开始,升序,左右闭区间 |
ZRANGEBYSCORE | 按照score排序后,获取指定score范围内的元素 | zrangebyscore key min max | 升序,左右闭区间 |
ZDIFF/ZINTER/ZUNION | 求差集、交集、并集 | 参考set类型 |
注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可,例如:
升序获取sorted set 中的指定元素的排名:ZRANK key member
降序获取sorted set 中的指定元素的排名:ZREVRANK key memeber
练习题:
1.将班级的下列学生得分存入Redis的SortedSet中:
2实现下列功能:
通用指令是不分数据类型的,无论哪种数据类型都可以使用的指令,常见的有:
指令 | 作用 | 语法 | 备注 |
---|---|---|---|
KEYS | 查看符合模板的所有key | keys pattern | keys * 查询所有,key a*查询以a开头的key… |
DEL | 删除一个或多个指定的key,返回值为成功删除的key | del key [key…] | |
EXISTS | 判断一个或多个key是否存在,返回值为存在的key的数量 | exists key [key…] | |
EXPIRE | 给一个key设置有效期,有效期到期时该key会被自动删除 | expire key seconds | |
TTL | 查看一个KEY的剩余有效期 | ttl key | 返回值为-2说明key已经被移除,返回值为-1代表永久有效 |
Redis没有类似MySQL中的Table的概念,我们该如何区分不同类型的key呢?
例如,需要存储用户、商品信息到redis,假如有一个用户id是1,有一个商品id恰好也是1,此时如果使用id作为key,那就会发生冲突,那么在这种情况下该怎么办?
针对上述情况,我们可以通过给key添加前缀加以区分,Redis的key允许有多个单词形成层级结构,多个单词之间用’:'隔开,格式如下:
项目名:业务名:类型:id
这个格式并非固定,也可以根据自己的需求来删除或添加词条。这样以来,我们就可以把不同类型的数据区分开了。从而避免了key的冲突问题。
例如我们的项目名称叫Shopping ,有user和product两种不同类型的数据,那我们可以这样定义key:
user相关的key:Shopping:user:1
product相关的key:Shopping:product:1
如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储:
KEY | VALUE |
---|---|
Shopping:user:1 | {“id”:1, “name”: “Jack”, “age”: 21} |
Shopping:product:1 | {“id”:1, “name”: “小米11”, “price”: 4999} |
并且,在Redis的桌面客户端RESP中,还会以相同前缀作为层级结构,让数据看起来层次分明,关系清晰: