Redis成绩排行榜实现(Set)

发布于 2021-04-01  696 次阅读


(项目地址:C:\Users\橙汁\Desktop\个人学习代码\redis-study\springboot-redis)

为什么会用到Redis?

比如说我有一个做题系统,任何人在任何时间都可以做题,并且所有的用户有一个排行榜,做的题越多分数越高,那么这个排行榜的数据应该是经常变化的。

如果现在同时有10w人在线做题(虽然一般并不可能),当他们提交题目之后希望马上看到排行榜的刷新,并且有大量的读操作,那么该排行榜就可以当作热点数据

此时如果使用Mysql查询就会比较慢,这对人来说无疑是沮丧的,因此我们可以把排行榜这类数据使用Redis来存储。

 

前提:

  1. 排行榜是去重的,而且应该是有序的,那么我们可以考虑使用Redis的Zset数据结构来做;
  2. Springboot环境下操作Redis,需要熟知RedisTemplate(当然也可以使用Redis-cli)

实现:

一、配置文件

application.yml:

spring:
redis:
host: 127.0.0.1
port: 6379
password:
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 500
min-idle: 0
lettuce:
shutdown-timeout: 0ms

二、导入依赖

<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20200518</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>

 

三、代码实现:

 

package com.kuang;

import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.HashSet;
import java.util.Set;

/**
* 2021.4.1
* 学习了Redis的基本数据类型,决定在Springboot环境下进行使用
*
* 目的:实现学习成绩排行榜
* @param key 键
* @param item 项
*
* 采用Zset有序集合
*/
@SpringBootTest
public class YangTest {

//注入rediTemplate
@Autowired
private RedisTemplate<String,String> redisTemplate;

//初始化Redis键,全局不可变
private final String INDEX = "index";

/*1.批量添加学生成绩,模拟从数据库中获得*/
@Test
void batchAdd(){

//创建存放集合
Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>();
//获取开始时间
long start = System.currentTimeMillis();
for (int i = 0; i < 100 ; i++){
//新增每个人的成绩,每个人之间相差2分
DefaultTypedTuple<String> tuple = new DefaultTypedTuple<String>("张三"+i,1D+i*2);
//添加进Set集合
tuples.add(tuple);
}
System.out.println("循环消耗时间:"+(System.currentTimeMillis()-start));

//执行Redis插入操作!!! 需要键和值(直接传入tuples自动全部写入)
Long num = redisTemplate.opsForZSet().add(INDEX, tuples);
System.out.println("批量新增成绩所消耗的时间:"+(System.currentTimeMillis()-start));
System.out.println("新增行数:"+num);
}

/*2.获取当前的同学总数(基数)*/
@Test
void getCardNum(){
Long card = redisTemplate.opsForZSet().zCard(INDEX);
System.out.println("计科1811班上同学总数为:"+card);
}

/*3.根据1获取排行榜前10*/
@Test
void TopTen(){
//调用reverseRange()方法,返回一个Set对象(仅仅包含名字)
Set<String> range = redisTemplate.opsForZSet().reverseRange(INDEX,0,10);
//使用JSON.toJSONString(Object)将对象转换为JSON字符串
System.out.println("计科1811班前十名高手姓名:"+JSON.toJSONString(range));
//调用reverseRangeWithScores()方法,返回一个Set对象(包含名字+成绩)
Set<ZSetOperations.TypedTuple<String>> rangeWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(INDEX, 0, 10);
//使用JSON.toJSONString(Object)将对象转换为JSON字符串
System.out.println("前十高手的名字及成绩:"+JSON.toJSONString(rangeWithScores));
}

/*4.现在来了个大佬杨某,新增杨某一个人的分数*/
@Test
void add(){
redisTemplate.opsForZSet().add(INDEX,"杨某",196);
}

/*5.大家都很好奇大佬杨某考了多少名,一起刷新排行榜看看吧*/
//重新调用TopTen()

/*6.为了装逼,杨某没有去看前十排行榜,他选择了看自己的个人排名*/
@Test
void YangRank(){
//注意:调用reverseRank()方法,返回其排名数值
Long rankNum = redisTemplate.opsForZSet().reverseRank(INDEX, "杨某");
//下标从0开始,第一名的rankNum为0,所以这里要+1
System.out.println("杨某的排名为:"+(rankNum+1));
//注意:调用score()方法,返回其具体成绩
Double score = redisTemplate.opsForZSet().score(INDEX, "杨某");
System.out.println("杨某的成绩为:"+score);
}

/*7.虽然成绩很好,但杨某觉得自己应该不是第三,自己做好了第一的准备啊,于是他找老师理论,核对卷子发现老师少给了三分*/
/*8.老师表示立即给杨某修改*/
@Test
void TeachIncrScore(){
//调用incrementScore()方法
Double score = redisTemplate.opsForZSet().incrementScore(INDEX, "杨某", 3);
System.out.println("修改之后的成绩为:"+score);
}

/*9.老师想要统计分数区间的人数*/
@Test
void getPeoNum(){
Long count = redisTemplate.opsForZSet().count(INDEX, 195, 200);
System.out.println("分数在195~200之间的人数为:"+count);
}

}


四、总结

上述例子中,我们实现了批量增加,单个增加,修改成绩,获取基数,获取排行榜,获取单人排行,获取区间人数等操作,但RedisTemplate还提供了其他的方法

详情可见:

https://blog.csdn.net/qq_39071667/article/details/88867677


她喜欢所以就做咯