1-Redis - 数据类型
about
Redis中用的最多的数据类型有String、Hash、List、Set、Zset。
而Redis的key都是字符串,不同的数据类型指的是value的类型。
key的通用操作
在Redis中的终端中,一般命令无大小写之分,也可以使用tab键补全和切换命令。
127.0.0.1:6379> keys * # 返回所有的key,尽量避免在生产中使用
127.0.0.1:6379> keys k* # 可以用模糊匹配来替代 keys *
127.0.0.1:6379> keys k1 # 返回k1
127.0.0.1:6379> type k1 # 返回k1的value类型
127.0.0.1:6379> DEL k2 # 删除一个key
127.0.0.1:6379> EXISTS k2 # 判断 key 是否存在
127.0.0.1:6379> RENAME k3 k33 # 重命名
设置键值对的生存时间:
# EXPIRE/PEXPIRE 以秒/毫秒为单位设置生存时间
# TTL/PTTL 以秒/毫秒为单位返回剩余的生存时间
# PERSIST 即在生存时间内,取消生存时间设置
127.0.0.1:6379> EXPIRE k2 20 # 为 k2 设置生存时间为20秒
(integer) 1
127.0.0.1:6379> ttl k2 # 返回 k2 剩余的生存时间
(integer) 15
127.0.0.1:6379> PERSIST k2 # 取消生存时间设置
(integer) 1
127.0.0.1:6379> ttl k2 # 表示没有设置生存时间
(integer) -1
注意,不要将大量的键值对设置为同一时间失效,避免造成缓存雪崩!
string
应用场景:
- session 共享
- 常规计数:评论数、粉丝数、礼物数、订阅数
字符串的相关操作
# 如果key存在,则覆盖原来的value值,若key不存在,就设置key和value
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> get hello
"world"
# 先get再set
127.0.0.1:6379> getset k1 v1 # 先get,因为k1不存在,返回空nil,然后在设置一个值v1
(nil)
127.0.0.1:6379> get k1 # 可以看到设置成功了
"v1"
127.0.0.1:6379> getset k1 v2 # 先get,获取到的值是上一次的结果,再set一个新值
"v1"
127.0.0.1:6379> get k1 # 最新值
"v2"
# 在set的时候指定存活时间,在存活时间内,可以获取到该值
127.0.0.1:6379> setex k2 10 v2
OK
127.0.0.1:6379> ttl k2
(integer) 6
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k2
(nil)
# 如果key不存在,就设置一个key:value,如果key存在则什么都不做
127.0.0.1:6379> setnx k3 v3
(integer) 1
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379> setnx k3 v33
(integer) 0
127.0.0.1:6379> get k3
"v3"
# 批量设置和批量获取
127.0.0.1:6379> mset k4 v4 k5 v5 k6 v6
OK
127.0.0.1:6379> mget k4 k5 k6
1) "v4"
2) "v5"
3) "v6"
# 删除key
127.0.0.1:6379> del k1
(integer) 1
# 追加值,若key不存在,相当于add,若key存在,就是相当于拼接字符串
127.0.0.1:6379> get k5 # k5存在
"v5"
127.0.0.1:6379> append k5 5 # 因为k5存在,所以拼接字符串,并返回拼接后的字符串长度
(integer) 3
127.0.0.1:6379> get k5 # 拼接后的value
"v55"
127.0.0.1:6379> del k5
(integer) 1
127.0.0.1:6379> append k5 5 # k5不存在,相当于添加一个key:value 并返回value的长度
(integer) 1
127.0.0.1:6379> get k5 # 添加后的值
"5"
# 为指定字节位置的元素替换为指定值
127.0.0.1:6379> set k7 0123456789
127.0.0.1:6379> setrange k7 5 A # 将第5个字节位置的值替换为 A
(integer) 10
127.0.0.1:6379> get k7 # 替换后的结果
"01234A6789"
127.0.0.1:6379> setrange k7 12 BC # 如果指定的字节数超出字符串长度,就补零
(integer) 14
127.0.0.1:6379> get k7
"01234A6789\x00\x00BC"
127.0.0.1:6379> setrange k7 6 7 BC # 不允许这种将第6~7字节位置的元素替换为指定值
(error) ERR wrong number of arguments for 'setrange' command
# 判断key是否存在,存在返回1,否则返回0
127.0.0.1:6379> EXISTS k1
(integer) 1
# 如果key存在,返回值的长度,否则返回0
127.0.0.1:6379> get k1
"v2"
127.0.0.1:6379> STRLEN k1
(integer) 2
127.0.0.1:6379> STRLEN k222 # k222不存在
(integer) 0
# 返回字符串指定字节范围的值
127.0.0.1:6379> set k7 0123456789
OK
127.0.0.1:6379> GETRANGE k7 1 5 # 第1~5个字节范围内的值
"12345"
127.0.0.1:6379> GETRANGE k7 5 15 # 第5~15个字节范围内的值,如果字符串长度不够,以起始位置开始,有多少返回多少
"56789"
127.0.0.1:6379> GETRANGE k7 15 20 # 起始和结束范围都不在字符串范围内,返回空
""
上例中有对范围设置值或者取值的操作,但谨记,不能对中文这么做,因为一个中文由多个字节组成。
计数器功能
127.0.0.1:6379> INCR num # 每次调用incr命令,num值自加一
(integer) 1
127.0.0.1:6379> INCR num
(integer) 2
127.0.0.1:6379> INCRBY num 1000 # 一次性累加指定数
(integer) 1002
127.0.0.1:6379> INCRBY num 1000
(integer) 2002
127.0.0.1:6379> INCR num
(integer) 2003
127.0.0.1:6379> DECR num # decr 使num自减一
(integer) 2002
127.0.0.1:6379> DECR num
(integer) 2001
127.0.0.1:6379> DECRBY num 1000 # 一次性累减指定数
(integer) 1001
127.0.0.1:6379> DECRBY num 1000
(integer) 1
127.0.0.1:6379> get num # 可以通过get获取该计数器的值
"1"
hash
应用场景:
- 数据缓存
类似python的字典,但是成员只能是string,专门用于结构化的数据信息。
使用hmset
来声明一个hash类型的一组或者多组键值对;使用hmget
来获取一组或者多组键值对的值:
# 增,若某字段存在,就更新其value,否则就是添加key:value
127.0.0.1:6379> hmset user_1 id 1 name zhangkai age 18 gender m
OK
127.0.0.1:6379> hmset user_2 id 2 name wangkai age 20 gender m
OK
# 查
127.0.0.1:6379> hget user_1 name # 获取指定字段的值
127.0.0.1:6379> hmget user_1 id name age # 获取多个字典的值
127.0.0.1:6379> hgetall user_1 # 返回所有字段和值
127.0.0.1:6379> HKEYS user_1 # 返回key中所有的字段
127.0.0.1:6379> HVALS user_1 # 返回key中所有的字段值
127.0.0.1:6379> HEXISTS user_1 name # 判断指定字段是否存在,存在返回1,否则返回0
127.0.0.1:6379> HLEN user_1 # 返回key中所有字段的数量
# 改
127.0.0.1:6379> HINCRBY user_1 age 1 # 为整型字段的值加固定数字
127.0.0.1:6379> hget user_1 age
127.0.0.1:6379> hset user_1 name zhangkai2 # 为指定字段重新赋值
list
应用场景:
- 消息队列系统
- 最新的微博消息,比如我们将最新发布的热点消息都存储到Redis中,只有翻看"历史久远"的个人信息,这类冷数据时,才去MySQL中查询
列表的特点:
- 后插入的在最前面,相当于每次都默认在索引0前面做插入操作。这个特性相当于微信朋友圈,最新发布的的动态在最上面。
- 列表内每一个元素都有自己的下标索引,从左到右,从0开始;从右到左,从
-1
开始,这跟Python中的列表一样。 - 列表中的元素可重复。
127.0.0.1:6379> LPUSH msg "message day1"
(integer) 1
127.0.0.1:6379> LPUSH msg "message day2"
(integer) 2
127.0.0.1:6379> LPUSH msg "message day3"
(integer) 3
127.0.0.1:6379> LPUSH msg "message day4"
(integer) 4
127.0.0.1:6379> LRANGE msg 0 -1
1) "message day4"
2) "message day3"
3) "message day2"
4) "message day1"
来看操作:
# 增
LPUSH l1 a b # 如果 l1 不存在就创建,然后将 a b 插入到 l1 中,如果 l1 存在,直接将 a b 插入到 l1 中
LPUSHX l1 c # 如果 key 存在则插入,不存在则什么也不做
LINSERT l1 before a a1 # 在元素 a 前面插入 a1
LINSERT l1 after a a2 # 在元素 a 后插入 a2
RPUSH l1 1 # 在列表尾部追加 元素 1
RPUSH l1 2 3 # 在列表尾部先追加 2 再追加 3
RPUSHX l1 4 # 如果列表 l1 存在就将元素4追加到列表尾部,如果列表不存在则什么也不做
# 查,根据索引下标取值
LRANGE l1 0 -1 # 从索引0开始取到-1,也就是从头取到尾,获取列表中的所有元素
LRANGE l1 0 2 # 取索引 0 1 2 三个索引对应的元素
LRANGE l1 0 0 # 取索引 0 对应的元素
LRANGE l1 10 15 # 如果索引不在合法范围内,则取空
LINDEX l1 1 # 根据索引下标返回元素
# 删除
LPOP l1 # 抛出列表头部元素
RPOP l1 # 抛出列表尾部元素
RPOPLPUSH l1 l2 # 将列表 l1 尾部的元素抛出并且添加到列表 l2 中
LREM l1 2 a1 # 从左到右,删除指定个数的元素 a1 ,本示例中,若 a1 有 1 个,就删一个,若 a1 有 3 个或者更多,也就删除 2 个
LTRIM l1 2 4 # 保留索引2-4的元素,其余删除
# 改
LSET l1 0 a # 将列表索引为0的元素修改为指定值,如果索引位置不存在则报错
set
集合的应用场景:
- 适用于各种需要求交集、并集、差集的场景,比如共同好友,共同关注的场景。
- 另外这里的集合也有数学上的集合特性,去重,交、并、差集的运算。
基础操作:
# 增,声明key并添加 a b c 三个元素
127.0.0.1:6379> sadd s1 a b c
# 查
127.0.0.1:6379> SMEMBERS s1 # 返回 s1 中所有元素
127.0.0.1:6379> SCARD s1 # 返回 s1 中元素的个数
127.0.0.1:6379> SRANDMEMBER s1 # 随机返回集合中的元素
127.0.0.1:6379> SISMEMBER s1 a # 判断元素 a 是否存在
# 删除
127.0.0.1:6379> SPOP s1 # 随机删除一个元素,并将这个元素返回
127.0.0.1:6379> del s1 # 删除 key
# 移动
127.0.0.1:6379> smove s1 s2 a # 将元素 a 从s1移动到s2中,如果s2不存在,就先创建再移动
再来看集合的运算。我们来个示例,有个需求,现有个培训学校欧德博爱开设了Python和Linux两门课程,来学习的同学都有如下情况:
- 有的同学学习Linux
- 有的学习Python
- 还有的既学了Linux又学了Python
那现在问题来了,我们要对这些同学的情况做统计,比如找出两门课都报了的同学?
# 先把数据准备好
127.0.0.1:6379> SADD python xiaoA xiaoB Huluwa xiaoC xiaoMaque
(integer) 5
127.0.0.1:6379> SADD linux xiaoC xiaoMaque xiaoD xiaoE xiaoDongbei
(integer) 5
# 求交集,找出即学习了Python又学习了Linux的同学
127.0.0.1:6379> SINTER python linux
1) "xiaoC"
2) "xiaoMaque"
# 求交集,找出即学习了Python又学习了Linux的同学,并将结果保存到集合tmp中,tmp不存在则先创建
127.0.0.1:6379> SINTERSTORE tmp python linux
(integer) 2
127.0.0.1:6379> SMEMBERS tmp
1) "xiaoMaque"
2) "xiaoC"
# 求并集,找出学习两门课程的所有人
127.0.0.1:6379> SUNION python linux
1) "xiaoE"
2) "xiaoA"
3) "xiaoB"
4) "xiaoD"
5) "xiaoDongbei"
6) "xiaoMaque"
7) "xiaoC"
8) "Huluwa"
# 求并集,找出学习两门课程的所有人,并将结果保存到集合tmp中,tmp不存在则先创建
127.0.0.1:6379> SUNIONSTORE tmp python linux
(integer) 8
127.0.0.1:6379> SMEMBERS tmp
1) "xiaoE"
2) "xiaoA"
3) "xiaoB"
4) "xiaoD"
5) "xiaoDongbei"
6) "xiaoMaque"
7) "xiaoC"
8) "Huluwa"
# 求差集,找出只学习了Python(或者Linux)课程的人
127.0.0.1:6379> SDIFF python linux # 只学习Python课程的人
1) "xiaoA"
2) "xiaoB"
3) "Huluwa"
127.0.0.1:6379> SDIFFSTORE tmp python linux # 只学习Python课程的人,并将结果保存到集合tmp中,tmp不存在则先创建
(integer) 3
127.0.0.1:6379> SMEMBERS tmp
1) "xiaoA"
2) "xiaoB"
3) "Huluwa"
127.0.0.1:6379> SDIFF linux python # 只学习Linux课程的人
1) "xiaoDongbei"
2) "xiaoE"
3) "xiaoD"
# # 只学习Linux课程的人,并将结果保存到集合tmp中,tmp不存在则先创建
127.0.0.1:6379> SDIFFSTORE tmp linux python
(integer) 3
127.0.0.1:6379> SMEMBERS tmp
1) "xiaoDongbei"
2) "xiaoE"
3) "xiaoD"
Zset
有序集合在集合的基础上增加了排序功能,比如以点击数为条件进行排序。
有序集合的典型应用场景:
- 各种排行榜,音乐排行榜、热点新闻榜.....
在有序集合中,我们一般称其元素为成员,其成员对应的值为分数。
基础操作:
# 增加
127.0.0.1:6379> ZADD top 0 xuwei 0 zhoujielun
(integer) 2
# 查, withscores是可选参数,表示同时返回其成员和其得分
127.0.0.1:6379> ZSCORE top xuwei # 返回top中,指定成员的分数,如果指定成员不存在则返回nil
"0"
127.0.0.1:6379> ZSCORE top zhangkai
(nil)
# 返回top中所有成员,默认以分数大小升序排序,分值相同按ASCII编码排序
127.0.0.1:6379> ZRANGE top 0 -1
1) "xuwei"
2) "zhoujielun"
127.0.0.1:6379> ZRANGE top 0 -1 WITHSCORES
1) "xuwei"
2) "0"
3) "zhoujielun"
4) "0"
# 返回成员在有序集合中的索引下标,如果成员不存在返回nil
127.0.0.1:6379> ZRANK top xuwei
(integer) 0
127.0.0.1:6379> ZRANK top zhangkai
(nil)
# 返回top中成员的数量
127.0.0.1:6379> ZCARD top
(integer) 2
# 返回topN中所有成员,-inf表示第一个成员,+inf表示最后一个成员,结果默认以其分数的大小排序
127.0.0.1:6379> ZRANGEBYSCORE top -inf +inf
1) "xuwei"
2) "zhoujielun"
127.0.0.1:6379> ZRANGEBYSCORE top -inf +inf WITHSCORES
1) "xuwei"
2) "0"
3) "zhoujielun"
4) "0"
# 返回topN中所有成员,并且以索引从大到小排序
127.0.0.1:6379> ZREVRANGE top 0 -1
1) "zhoujielun"
2) "xuwei"
127.0.0.1:6379> ZREVRANGE top 0 -1 WITHSCORES
1) "zhoujielun"
2) "0"
3) "xuwei"
4) "0"
# 返回topN中 0 <= index <= 2 索引范围内的成员,不在范围内返回空
127.0.0.1:6379> ZREVRANGE top 0 2
1) "zhoujielun"
2) "xuwei"
127.0.0.1:6379> ZREVRANGE top 0 2 WITHSCORES
1) "zhoujielun"
2) "0"
3) "xuwei"
4) "0"
127.0.0.1:6379> ZREVRANGE top 3 5 WITHSCORES
(empty list or set)
# 返回topN中分数在 20 <= 分数 <= 200 这个范围内的成员的数量
127.0.0.1:6379> ZADD top 20 xuwei 80 zhoujielun 100 daolang 120 zhaolei # 先搞个数据
127.0.0.1:6379> ZCOUNT top 20 200
(integer) 4
# 返回topN中分数在 20 <= 分数 <= 200 这个范围内的成员
127.0.0.1:6379> ZRANGEBYSCORE top 20 200
1) "xuwei"
2) "zhoujielun"
3) "daolang"
4) "zhaolei"
127.0.0.1:6379> ZRANGEBYSCORE top 20 200 WITHSCORES
1) "xuwei"
2) "20"
3) "zhoujielun"
4) "80"
5) "daolang"
6) "100"
7) "zhaolei"
8) "120"
# 返回topN中分数范围在 100 <= 的 <= 20 范围内的成员,并以的的大小降序排序
127.0.0.1:6379> ZREVRANGEBYSCORE top 100 20
1) "daolang"
2) "zhoujielun"
3) "xuwei"
127.0.0.1:6379> ZREVRANGEBYSCORE top 100 20 WITHSCORES
1) "daolang"
2) "100"
3) "zhoujielun"
4) "80"
5) "xuwei"
6) "20"
# 改
# 为指定成员重新赋值
127.0.0.1:6379> ZADD top 30 xuwei
(integer) 0
# 为指定成员增加指定分数,并返回增加后的分数
127.0.0.1:6379> ZINCRBY top 10 xuwei
"40"
# 删除
# 删除分数在指定范围内的成员,并返回删除成员的数量
127.0.0.1:6379> ZREMRANGEBYSCORE top 80 100
(integer) 2
# 删除topN中指定索引范围内 0 <= index <= 1 的成员
127.0.0.1:6379> ZREMRANGEBYRANK top 0 1
(integer) 2
# 删除topN中一个或者多个成员,返回实际删除的个数,没有找到key返回0
127.0.0.1:6379> ZREMRANGEBYRANK top 0 1
(integer) 2
127.0.0.1:6379> DEL top
(integer) 1
来个音乐排行榜的示例:
# 创建初始的音乐排行榜,初始每首歌播放量都是0
ZADD top 0 aiqing 0 guxiang 0 lanlianhua 0 shiguang
# 模拟每首歌的播放量
ZINCRBY top 123 aiqing
ZINCRBY top 223 guxiang
ZINCRBY top 223 lanlianhua
ZINCRBY top 23 shiguang
# 返回播放量前三名的歌名
127.0.0.1:6379> ZREVRANGE top 0 2 WITHSCORES
1) "aiqing"
2) "123"
3) "shiguang"
4) "0"
5) "lanlianhua"
6) "0"
that's all,see also:
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | Redis Zrangebyscore 命令