redis使用场景(zset)
前言
zset,有序set。看过我redis第一篇文章的小伙伴应该都知道,底层数据结构为跳表,通过跳表结构减小插入排序的时间复杂度(这里不知道的同学可以去看下第一篇文章)。同时查询时间复杂度也会减小。那么有序集合有什么作用呢?我们首先看一下redis zset的相关命令。
// 常见命令
#增加元素 (增加元素 A B C 对应积分 1 2 3 (排序的根据))
zadd myzset 1 A 2 B 3 C
#删除元素
zrem myzset A
#集合数量
zcard myzset
#增加某个元素的积分 加1
zincrby myzset increment A
#返回指定key对应的有序集合中,分值在min~max之间的元素个数
zcount myzset 0 10 (返回积分在0-10之间的元素数量)
#返回指定key对应的有序集合中,指定元素member在集合中排名,从0开始切分值是从小到大升序
zrank myzset A
#返回指定key对应的集合中,指定member在其中的排名,注意排名从0开始且按照分值从大到小降序
zrevrank myzset A
#返回指定key中的集合中指定member元素对应的分值
zscore myzset A
#返回指定key对应的有序集合中,索引在min~max之间的元素信息,如果带上 withscores 属性的话,可以将分值也带出来
zrange myzset 0 10 [withscores]
#指定key对应的集合中,分值在 start~end之间的降序,加上 withscores 的话可以将分值以及value都显示出来
zrevrange myzset 0 10 [withscores]
#同 zrange命令不同的是,zrange命令是索引在start~end范围的查询,而zrangebyscore命令是根据分值在start~end之间的查询且升序展示
zrangebyscore myzset 0 10 [withscores]
//当然 也有set的交并补命令 大家可以自行了解
正文
大家看了命令是不是颇有感触! 积分成为大多命令的关键字,通过积分我们会想到什么? 没错,排行榜! 这也就是redis zset的使用场景啦。在这个从出生就开始比来比去的时代,排行榜无非是从小就环绕着我们。(成绩排名什么的,最讨厌了。(#^.^#))。那么企业一般会用它来做什么呢? 微博的周榜?斗鱼刷礼物的日榜?运动步数排行?下面带大家了解下!
排行榜
排行榜的功能,无非增删改查,直接上代码。
@Autowired
private RedisTemplate redisTemplate;
//向排行榜中增加一个元素
public void add(Object element) throws ItemRankException {
redisTemplate.opsForZSet().incrementScore(getKey(), element, 1);
}
//取指定排名的数据
public Set<E> range(Long rankStart, Long rankEnd) {
return redisTemplate.opsForZSet().range(getKey(), rankStart, rankEnd);
}
//删除一个元素
public void remove(Long rankStart, Long rankEnd) {
redisTemplate.opsForZSet().removeRange(getKey(), rankStart, rankEnd);
}
//是否包含
public boolean constants(Object element) {
if (null == redisTemplate.opsForZSet().score(getKey(), element)) {
return false;
}
return true;
}
//根据分数获取元素
public Set rangByScore(Long startScore, Long endScore) {
return redisTemplate.opsForZSet().rangeByScore(getKey(), startScore, endScore);
}
//删除一个元素
public void remove(Object element) {
redisTemplate.opsForZSet().remove(getKey(), element);
}
延时队列
上篇文章,我们讲了异步消息队列,那这个延时队列是什么鬼?队列不应该是基于list做吗? 别着急,我带大家一起来看一下。首先,什么是延时队列? 顾名思义,延时就是不立即执行,等到合适的时间再执行。那么延时队列有什么使用场景呢?其实无处不在,比如订单超过30分钟未付款自动取消。那这跟有序队列有什么关系呢? 大家不妨转变一下思维,积分未必非要是分数,如果把它设置为该数据需要执行的时间呢?也就是排行榜维护的积分是执行时间,那么启动一个线程去消费排行榜的数据,不就做到了延时队列的效果。
//伪代码
@Autowired
private RedisTemplate redisTemplate;
public static String REDIS_KEY = "redis_key";
//入队
public void add(Object element) throws ItemRankException {
long curTime = System.currentTime();
redisTemplate.opsForZSet().incrementScore(REDIS_KEY, element, curTime+30*60*100);
}
//消费队列
public void consume(){
while(true){
Set set = redisTemplate.opsForZSet().range(REDIS_KEY , 0, 10);
if(CollectionUtils.isEmpty(set)){
Thread.sleep(100);
}
set.forEach(//todo 处理逻辑)
}
}
redis使用场景(hash)
redis的hash用来存储对象数据,但是通常会把对象序列化为string,然后使用string结构存储数据。 那么hash和string如何选取呢?我给大家列了一个表格,如下。
string | hash | |
效率 | 很高 | 高 |
容量 | 低 | 低 |
灵活性 | 低 | 高 |
序列化 | 简单 | 复杂 |
- 如果对象某个元素经常更改,可以用hash或string+json
- 如果对象中套对象(复杂的数据结构,使用string+json。
我觉得大部分情况用string+json就行了,hash很少用到。(个人见解)
结语
redis数据结构以及使用场景到此都已经讲完了,无论大家有没有收获,在这里都感谢大家阅读,欢迎批评指正。下面会介绍redis单机、哨兵、集群相关的知识,敬请期待。
关注不迷路