前言
高端的食材往往只需要最朴素的烹饪方式,忙碌(摸鱼)了两小时之后,陈师傅开始制作美食(coding)。
只见陈师傅小心翼翼的从箱子里捧出一本泛黄的祖传食谱《Redis食用指南》,缓缓翻开一页:数据结构和应用场景
数据结构和应用场景
String
字符串是redis最简单也是最常用的数据结构,使用场景非常广泛
热点数据缓存
可以存储简单的字符串信息,也可以将复杂结构数据序列化为字符串后存储
分布式锁
可以使用redis自带的set命令加nx、ex参数实现分布式锁
//nx保证原子性,ex保证原子性下设施过期时间
SET key value nx ex 10086
计数器
字符串结构是可以存储数字的,redis也提供了对数字的操作支持
//数值加减1操作
INCR key
DECR key
//数值加减n造作
INCRBY key n
DECRBY key n
Bit
BIT位图不是实际的数据类型,而是在String类型上定义的一组面向位的操作
签到记录、权限记录
可以使用bit来处理签到、打标签、等场景,此类场景的共性是:数值只有是或否(0和1)+ 被记录数据相对固定
,比如签到记录的就是某天是否打卡,权限记录的是某个权限是否存在,下面以签到举例
//签到(offset代表天数)
SETBIT key offset 1
//取消签到
SETBIT key offset 0
//统计签到天数
BITCOUNT key
布隆过滤器
布隆过滤器(Bloom Filter)是由 Bloom 于 1970 年提出的。我们可以把它看作由二进制向量(或者说位数组)和一系列随机映射函数(哈希函数)两部分组成的数据结构。
布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。
使用redis实现布隆过滤器,就需要使用一组多个散列函数分别计算目标值对应的数值,这几个数值就是偏移量,分别设置偏移量值为1即可,查询过程也是通过这组散列函数分别计算目标值对应数值,结果都为1代表命中,否则未命中
Hash
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
结构化对象存储
除了上面提到的使用字符串存储序列化后的对象,也可以使用hash存储对象信息
//存储对象所有属性
HMSET key field1 value1 field2 value2 [field3 value3]
//查询对象所有属性
HGETALL key
//修改对象某个属性
HSET key field1 value1
//查询对象某个属性
HGET key field1
两相对比,hash结构存储对象信息具有天然的优势:主要体现在对单个对象属性的查询和修改上,无需像字符串结构存取都只能全属性存全属性取
List
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
阻塞队列
reids的链表结构,可以轻松实现阻塞队列,可以使用左进右出的命令组成来完成队列的设计,可以在秒杀场景下可以用来销峰
//数据的生产者可以通过Lpush命令从左边插入数据
LPUSH key value1 [value2]
//多个数据消费者,可以使用BRpop命令阻塞的“抢”列表尾部的数据
BRPOP key
栈
相对于队列先进先出,栈是先进后出
//左边进
LPUSH key value1 [value2]
//左边出
LPOP key
Set
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
点赞、粉丝关注
点赞和粉丝属于同一类场景,共性是:一个用户针对一个主体只能操作一次 + 可查询是否操作过 + 可统计总数
//点赞、关注
SADD key member1
//取消点赞、取消关注
SREM key member1
//查询是否点赞、关注
SISMEMBER key member1
//查询点赞数、粉丝数
SCARD key
共同好友
共同好友就是取两个粉丝集合的交集
//取交集
SINTER key1 key2
Zset
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
排行榜
可以将需要排名的信息存储到有序集合,按特定排名查询。
//插入排名元素带分数
ZADD key score1 member1 [score2 member2]
//逆序排列所有成员(使用WITHSCORES参数返回分数)
ZREVRANGEBYSCORE key +inf -inf [WITHSCORES]
列表分页
使用有序集合做分页需要格外注意,分数不能有重复,因为相同分数有临界值问题,比如需要通过创建时间倒序排序场景,可以使用自增id作为分数(自增id相比创建时间同样能达到相同的排序效果,但没有时间可能重复的问题)
//插入排名元素带分数
ZADD key score1 member1 [score2 member2]
//取第一页数据(注意分数范围是正无穷大和负无穷大)
ZREVRANGEBYSCORE key +inf -inf [WITHSCORES] LIMIT 0 50
//取第二页数据(nextId为第一页最后一条数据的分数)
ZREVRANGEBYSCORE key nextId -inf [WITHSCORES] LIMIT 0 50
正序排序
有的小伙伴可能比较疑惑,翻遍了redis命令,都是倒序(从大到小)的排序,如果想正序排序怎么办?
思路:还是上面的例子,我们变通一下:分数 = 一个超大数值 - id
即可轻松解决
多级排序
还有小伙伴也比较疑惑,使用有序集合只能实现简单条件的排序,怎么实现多级的排序:比如一个班级的学生,通过成绩排序,成绩相同使用年龄排序,怎么实现?
思路:也需要变通一下:分数 = 成绩 * 10000 + 年龄 * 1
将需要排序的两个字段转换为一个数值,排序优先级高的放到高分位
总结
数据结构就像食材,深入认识食材的特点,加以精妙的烹饪技巧,便可轻松做出一道美食~