【面试题】redis五大数据类型、Bitmap
前言redis命令不区分大小写,但是key是区分大小写的。目前redis支持8种数据类型,最经典的还是前五种,本文只介绍前五种数据类型结构。string:最基本的数据类型,二进制安全的字符串,最大512M。hash:key-value对的一种集合。list:按照添加顺序保持顺序的字符串列表。set:无序的字符串集合,不存在重复的元素。sorted set:已排序的字符串集合。bitmap:更细化的
前言
redis命令不区分大小写,但是key是区分大小写的。
目前redis支持8种数据类型,最经典的还是前五种。
- string:最基本的数据类型,二进制安全的字符串,最大512M。
- list:按照添加顺序保持顺序的字符串列表。
- hash:key-value对的一种集合。
- set:无序的字符串集合,不存在重复的元素。
- sorted set:已排序的字符串集合。
- bitmap:更细化的一种操作,以bit为单位。
- hyperloglog:基于概率的数据结构。
- Geo:地理位置信息储存起来,并对这些信息进行操作
1. String
1.1 常用命令
set key value | 单个赋值 |
get key | 获取 |
del hello | 删除key |
exists key | key是否存在 存在返回1不存在返回0 |
setnx key value | 分布式锁(不存在赋值成功) |
ttl key | 查看过期时间 |
keys * | 查看所有key |
mset key1 value1 key2 value2 … | 批量赋值 |
mget key1 key2… | 批量获取 |
incr key / incrby key N | 自增1/自增N |
decr key / decrby key N | 自减1/自减N |
strlen key | 字符串的长度 |
getrange key 0 4 | 截取指定下标 |
setrange key 6 要替换的字符串 | 从指定位置开始替换 |
1.2 应用场景
1.2.1 验证码
1.2.2 商品库存
2. hash
2.1 常用命令
hset key key1 value1 | |
hmset set key key1 value1 key2 value2 … | 批量赋值 |
hget key key1 | |
hmget get key key1 key2 … | |
hgetall key | 获取所有字段值 |
hlen key | -获取某个key内全部数量 |
hdel key | 删除某个key |
2.2 应用场景
2.2.1 对象
2.2.2 购物车的实现
用户312 增加商品pid001 数量1
hset shopcar:userid:312 pid001 1
用户312 增加商品pid002 数量1
hset shopcar:userid:312 pid002 1
商品数量002增加1
hincrby shopcar:userid:312 pid002 1
商品总数
hlen shopcar:userid:312
商品全选
hgetall shopcar:userid:312
3. list(数据可重复)
3.1 常用命令
Lpush list one | 从左插入一个值 |
Rpush list four | 从右插入一个值 |
Lpush list two three | 从左插入多个值 |
Rpush list two three | 从右插入多个值 |
Linsert list before two three | two 之前插入 three |
Linsert list after two three | two 之后插入 three |
Lpop list | 移除最左边的元素 |
Rpop list | 移除最右边的元素 |
Lrem list 1 k | 移除一个指定元素k |
Lrem list 2 k | 移除两个指定元素k |
Lset list 0 one | 赋值列表指定下标元素(如果列表不存在或者列表指定下标不存在,赋值失败。) |
Llen list | 列表长度 |
Lrange list 0 1 | 查询指定下标范围元素 |
Lrange list 0 -1 | -1 即表示查询所有元素 |
Lindex list 0 | 下标从 0 开始 |
Ltrim list 1 2 | 截取下标 1 到 2 的元素 |
Rpoplpush list list2 | 移除列表最后一个元素并移动到新列表中 |
3.2 应用场景
list 实际是一个链表,左右都可以插入值。可以实现队列(先进先出),栈(先进后出)
3.2.1 微信订阅公众号推送文章
推送文章
lpush like:userid312 11
lpush like:userid312 22
获取文章列表
lrange like:userid312 0 -1
3.2.2 取最新N个数据的操作(记录前N个最新登陆的用户Id列表)
//记录前N个最新登陆的用户Id列表,超出的范围可以从数据库中获得。
//把当前登录人添加到链表里
ret = r.lpush("login:last_login_times", uid)
//保持链表只有N位
ret = redis.ltrim("login:last_login_times", 0, N-1)
//获得前N个最新登陆的用户Id列表
last_login_list = r.lrange("login:last_login_times", 0, N-1)
4. set(数据不可重复)
4.1 常用命令
Sadd set hello | 插入元素 |
Smembers set | 取出所有元素 |
Sismember set hello | 存在返回 1,不存在返回0 |
Scard set | 元素个数 |
Srandmember set | 随机元素 |
Spop set | 随机弹出元素 |
Sdiff set1 set2 | 取 set1 对于 set2 的差集 |
Sinter set1 set2 | 取 set1 和 set2 的交集 |
Sunion set1 set2 | 取 set1 和 set2 的并集 |
Srem set world | 删除指定元素 |
Smove set1 set2 hello | 移动 set1 中的 hello 到 set2 中(set2不存在则创建) |
4.2 应用场景
4.2.1 微信小程序抽奖
4.2.2 朋友圈点赞
4.2.3 共同关注好友
4.2.4 可能认识的人
5. zset
5.1 常用命令
zadd key score1 member1 score2 member2 … | 添加一个元素以及该元素分数 |
zrem key member1 | 移除元素 |
Zcard zset | 元素个数 |
zincrby key N member1 | 增加某个元素的分数 |
zscore key member1 | 获取元素的分数 |
zrangescore key min max | 获取指定分数范围内的元素 |
zcount key min max | 获取指定分数范围内的元素数量 |
Zrange zset 0 1 | 正序查询指定下标范围 |
Zrangebyscore zset -inf +inf | 负无穷到正无穷正序排列 |
Zrem zset three | 移除指定元素 |
5.2 应用场景
5.2.1 销售排行榜
5.2.2 热搜
6.0 Bitmap
6.1 常用命令
setbit key offset value | 设置 key 的第 offset 位为 value (1 或 0) |
getbit key offset | 获取 offset 设置的值,未设置过默认返回 0。 |
bitcount key [start, end] | 统计 key 上位为 1 的个数 |
6.2 应用场景
6.2.1 记录考勤
使用 bitmap 来记录一周的打卡记录(1 为打卡,0 为没打卡)
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
//统计这周打卡的记录
127.0.0.1:6379> bitcount sign
(integer) 3
7.0 案例分析
7.1 显示最新的项目列表
下面这个语句常用来显示最新项目,随着数据多了,查询毫无疑问会越来越慢。
SELECT * FROM foo WHERE … ORDER BY time DESC LIMIT 10
类似的问题就可以用Redis来解决。比如说,我们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上我们有一个“显示全部”的链接,点击后就可以获得更多的评论。
1.每次新评论发表时,我们会将它的ID添加到一个Redis列表:
LPUSH latest.comments <ID>
2.我们将列表裁剪为指定长度,因此Redis只需要保存最新的5000条评论:
LTRIM latest.comments 0 5000
3.每次我们需要获取最新评论的项目范围时,我们调用一个函数来完成(使用伪代码):
FUNCTION get_latest_comments(start, num_items):
id_list = redis.lrange("latest.comments",start,start+num_items - 1)
IF id_list.length < num_items
id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
END
RETURN id_list
END
这里我们做的很简单。在Redis中我们的最新ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。我们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
7.2 删除与过滤
我们可以使用LREM来删除评论。如果删除操作非常少,另一个选择是直接跳过评论条目的入口,报告说该评论已经不存在。
redis 127.0.0.1:6379> LREM KEY_NAME COUNT VALUE
有些时候你想要给不同的列表附加上不同的过滤器。如果过滤器的数量受到限制,你可以简单的为每个不同的过滤器使用不同的Redis列表。毕竟每个列表只有5000条项目,但Redis却能够使用非常少的内存来处理几百万条项目。
7.3 排行榜
另一个很普遍的需求是各种数据库的数据并非存储在内存中,因此在按得分排序以及实时更新这些几乎每秒钟都需要更新的功能上数据库的性能不够理想。
典型的比如那些在线游戏的排行榜,比如一个Facebook的游戏,根据得分你通常想要:
- 列出前100名高分选手
- 列出某用户当前的全球排名
这些操作对于Redis来说小菜一碟,即使你有几百万个用户,每分钟都会有几百万个新的得分。
模式是这样的,每次获得新得分时,我们用这样的代码:
ZADD leaderboard
你可能用userID来取代username,这取决于你是怎么设计的。
得到前100名高分用户很简单:ZREVRANGE leaderboard 0 99。
用户的全球排名也相似,只需要:ZRANK leaderboard 。
视频链接:https://www.bilibili.com/video/BV1S54y1R7SB?p=21&spm_id_from=pageDriver&vd_source=b901ef0e9ed712b24882863596eab0ca
更多推荐
所有评论(0)