点击上方“后端技术精选”,选择“置顶公众号”

技术文章第一时间送达!

作者:俊俊的小熊饼干

cnblogs.com/wenjunwei/p/9754346.html

题外话,今天推文2-7条对一些开发中常用的知识点做了分类总结,欢迎阅读!

需求

前段时间,做了一个世界杯竞猜积分排行榜。对世界杯64场球赛胜负平进行猜测,猜对+1分,错误+0分,一人一场只能猜一次。

1.展示前一百名列表。

2.展示个人排名(如:张三,您当前的排名106579)。


分析

一开始打算直接使用mysql数据库来做,遇到一个问题,每个人的分数都会变化,如何能够获取到个人的排名呢?数据库可以通过分数进行row_num排序,但是这个方法需要进行全表扫描,当参与的人数达到10000的时候查询就非常慢了。

redis的排行榜功能就完美锲合了这个需求。来看看我是怎么实现的吧。


实现

一.redis sorts sets简介

Sorted Sets数据类型就像是set和hash的混合。与sets一样,Sorted Sets是唯一的,不重复的字符串组成。可以说Sorted Sets也是Sets的一种。

Sorted Sets是通过Skip List(跳跃表)和hash Table(哈希表)的双端口数据结构实现的,因此每次添加元素时,Redis都会执行O(log(N))操作。所以当我们要求排序的时候,Redis根本不需要做任何工作了,早已经全部排好序了。元素的分数可以随时更新。

二.springboot 中使用RedisTemplate

本文主要通过redisTemplate来操作redis,当然也可以使用redis-client,看个人喜好.

我在本机开启了一个单点的redis,配置文件如下

server:  port: 9001spring:  redis:    database: 0    url: redis://user:123@127.0.0.1:6379    host: 127.0.0.1    password: 123    port: 6379    ssl: false    timeout: 5000

Maven依赖引入如下

<parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>2.0.4.RELEASE</version></parent><dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-redis</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>        </dependency></dependencies>

三.代码实现

1.注入redis,将key声明为常量SCORE_RANK

    @Autowired    private StringRedisTemplate redisTemplate;    public static final String SCORE_RANK = "score_rank";

2.新增默认排行数据

这里使用for循环创建集合,再使用批量新增10万条数据

    /**     * 批量新增     */    @Test    public void batchAdd() {        Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>();        long start = System.currentTimeMillis();        for (int i = 0; i < 100000; i++) {            DefaultTypedTuple<String> tuple = new DefaultTypedTuple<>("张三" + i, 1D + i);            tuples.add(tuple);        }        System.out.println("循环时间:" +( System.currentTimeMillis() - start));        Long num = redisTemplate.opsForZSet().add(SCORE_RANK, tuples);        System.out.println("批量新增时间:" +(System.currentTimeMillis() - start));        System.out.println("受影响行数:" + num);    }

输出

循环时间:56批量新增时间:1015受影响行数:100000

3.获取前10名(根据分数倒序)

提供了两种获取方法,返回值一个带有score,一个没有

    /**     * 获取排行列表     */    @Test    public void list() {        Set<String> range = redisTemplate.opsForZSet().reverseRange(SCORE_RANK, 0, 10);        System.out.println("获取到的排行列表:" + JSON.toJSONString(range));        Set<ZSetOperations.TypedTuple<String>> rangeWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(SCORE_RANK, 0, 10);        System.out.println("获取到的排行和分数列表:" + JSON.toJSONString(rangeWithScores));    }

输出

获取到的排行列表:["张三99999","张三99998","张三99997","张三99996","张三99995","张三99994","张三99993","张三99992","张三99991","张三99990","张三99989"]获取到的排行和分数列表:[{"score":100000.0,"value":"张三99999"},{"score":99999.0,"value":"张三99998"},{"score":99998.0,"value":"张三99997"},{"score":99997.0,"value":"张三99996"},{"score":99996.0,"value":"张三99995"},{"score":99995.0,"value":"张三99994"},{"score":99994.0,"value":"张三99993"},{"score":99993.0,"value":"张三99992"},{"score":99992.0,"value":"张三99991"},{"score":99991.0,"value":"张三99990"},{"score":99990.0,"value":"张三99989"}]

4.新增李四的分数

将“李四”加入到排行榜中,redis会在插入的时候进行,在取出的时候就可以直接取出,不需要再做排序操作

    /**     * 单个新增     */    @Test    public void add() {        redisTemplate.opsForZSet().add(SCORE_RANK, "李四", 8899);    }

5.获取李四单人的排行

    /**     * 获取单个的排行     */    @Test    public void find(){        Long rankNum = redisTemplate.opsForZSet().reverseRank(SCORE_RANK, "李四");        System.out.println("李四的个人排名:" + rankNum);        Double score = redisTemplate.opsForZSet().score(SCORE_RANK, "李四");        System.out.println("李四的分数:" + score);    }

输出

李四的个人排名:91101李四的分数:8899.0

6.统计分数区间人数

redis还提供了统计分数区间的方法,如下

    /**     * 统计两个分数之间的人数     */    @Test    public void count(){        Long count = redisTemplate.opsForZSet().count(SCORE_RANK, 8001, 9000);        System.out.println("统计8001-9000之间的人数:" + count);    }

输出

统计8001-9000之间的人数:1001

7.获取集合的基数(数量大小)

    /**     * 获取整个集合的基数(数量大小)     */    @Test    public void zCard(){        Long aLong = redisTemplate.opsForZSet().zCard(SCORE_RANK);        System.out.println("集合的基数为:" + aLong);    }

输出

集合的基数为:100001

8.使用加法操作分数

这个方法是直接在原有的score上使用加法;如果没有这个元素,则会创建,并且score初始为0.再使用加法

    /**     * 使用加法操作分数     */    @Test    public void incrementScore(){        Double score = redisTemplate.opsForZSet().incrementScore(SCORE_RANK, "李四", 1000);        System.out.println("李四分数+1000后:" + score);    }

输出

李四分数+1000后:9899.0

四.归纳

在以上测试类中我们使用了redis的那些功能呢?在以上的例子中我们使用了单个新增,批量新增,获取前十,获取单人排名这些操作,但是redisTemplate还提供了更多的方法。扩展:Redis底层数据结构

新增or更新

有三种方式,一种是单个,一种是批量,对分数使用加法(如果不存在,则从0开始加)。

//单个新增or更新Boolean add(K key, V value, double score);//批量新增or更新Long add(K key, Set<TypedTuple<V>> tuples);//使用加法操作分数Double incrementScore(K key, V value, double delta);

删除

删除提供了三种方式:通过key/values删除,通过排名区间删除,通过分数区间删除。

//通过key/value删除Long remove(K key, Object... values);//通过排名区间删除Long removeRange(K key, long start, long end);//通过分数区间删除Long removeRangeByScore(K key, double min, double max);

1.列表查询:

分为两大类,正序和逆序。以下只列表正序的,逆序的只需在方法前加上reverse即可

//通过排名区间获取列表值集合Set<V> range(K key, long start, long end);//通过排名区间获取列表值和分数集合Set<TypedTuple<V>> rangeWithScores(K key, long start, long end);//通过分数区间获取列表值集合Set<V> rangeByScore(K key, double min, double max);//通过分数区间获取列表值和分数集合Set<TypedTuple<V>> rangeByScoreWithScores(K key, double min, double max);//通过Range对象删选再获取集合排行Set<V> rangeByLex(K key, Range range);//通过Range对象删选再获取limit数量的集合排行Set<V> rangeByLex(K key, Range range, Limit limit);

2.单人查询

可获取单人排行,和通过key/value获取分数。以下只列表正序的,逆序的只需在方法前加上reverse即可

//获取个人排行Long rank(K key, Object o);//获取个人分数Double score(K key, Object o);

统计

统计分数区间的人数,统计集合基数。

//统计分数区间的人数Long count(K key, double min, double max);//统计集合基数Long zCard(K key);

结语

以上就是redis中使用排行榜功能的一些例子,和对redis的操作方法了。redis不仅仅只是作为缓存,它更是数据库,提供了许多的功能,我们都可以好好的利用。

在这里我使用redis来实现了世界杯积分排行的展示,无论是在批量更新或是获取个人排行等方便,都有着很高效率,也降低了对数据库操作的压力,达到了很好的效果。


技术经验交流:点击入群

看到这里了,就关注一个呗

Redis实现世界杯排行榜功能(实战)相关推荐

  1. redis ZSet实现排行榜功能

    一.写在前面 最近做完直播的基础功能后,又多了很多相关的需求,其中有一个就是直播间分享榜单的功能,顾名思义就是:分享本直播间并成功拉用户进来的数量做一个排行.比如我分享了这个直播间,别人通过我分享的直 ...

  2. 通过redis实现游戏排行榜功能

    需求说明 水晶数量排行榜 英雄熟练度排版 只排前一万名,玩家只能看到前200名的数据和自己的名次 每个排行榜实时刷新,玩家可以延迟5分钟查看榜单数据,但是自己的名次需要尽可能实时查看 分值一样,则先达 ...

  3. java基于Redis实现排行榜功能-附源码

    java基于Redis Zset实现排行榜功能 前言 做之前要思考的问题? Zset怎么存储需要的多个字段? 话不多说先上效果图 数据存储格式 代码 源码下载 闲暇之余,整理了一下之前利用Redis ...

  4. php redis 搜索,PHP+Redis有序集合(zset)实现博客园阅读排行榜功能

    许多网站都有排行榜的功能,比如球员人气榜单.阅读排行榜,对于一些小网站,通过查数据库就能实现排行榜的功能,但是对于稍微有点用户量而且还是实时排名的网站,使用一些关系型数据库如(MySQL.Oracle ...

  5. 使用 Redis 实现语音社交聊天室源码中的排行榜功能

    在语音社交聊天室源码中,排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般语音社交聊天室源码的排行榜都是有实效性的,比如"用户积分榜&quo ...

  6. php TP5 redis 实现排行榜功能 (日榜 周榜 月榜)

    php 结合tp5框架进行redis开发排行榜功能 下面附上我自己封装的redis类:数据持久化我目前是这么想的:同步存:然后定时检测是否过期,或者是否存在在去读数据遍历重新存储 <?php n ...

  7. 【Redis最佳实践】使用DCS Redis实现排行榜功能

    本节基于华为云DCS Redis实践所编写,用于指导您在以下场景使用DCS Redis实现排行榜功能. 目录 场景介绍 代码示例 实践指导 运行结果 华为云DCS Redis介绍 场景介绍 在网页和A ...

  8. Redis ZSet数据结构实现排行榜功能

    Redis ZSet数据结构实现排行榜功能 一. 使用场景 公司新项目要求, 实现每日排行榜以及各省排行榜 二. 功能实现(Java) 1. 排行榜数据插入及更新 /*** @date: 2022/1 ...

  9. 使用redis实现排行榜功能

    一.需求背景 最近项目需要做排行榜功能,实现员工邀请用户注册排行榜,要求是实时更新,查询要快.员工所属支行.二级行.省行,界面要根据条件显示排名数据.效果如下图所示: 原型图展示比较随意,用excel ...

最新文章

  1. 如何在HHDI中进行数据质量探查并获取数据剖析报告
  2. 致远oa系统报价_OA办公系统报价:企业内OA协同办公系统价格在多少比较合适?...
  3. TSM12M触摸芯片注意事项
  4. muduo学习笔记 线程类
  5. python爬虫需要什么知识-学习Python爬虫技术,需要掌握哪些web端的知识?
  6. 火种 ctf_分析我的火种数据
  7. 【CSS】css特殊性-优先级-权重
  8. kafka启动_Kafka安装部署——单节点
  9. iOS应用开发环境准备
  10. 你是否需要购买网站重构?
  11. event对象在IE和firefox下兼容写法
  12. (二) GNU/GCC 编译器及其编译流程概述
  13. java累积度分布,累积分布函数
  14. linux的字体文件夹在哪里,把windows下的字体安装到Linux系统下的方法介绍
  15. 单片机——LED点阵
  16. php把图片处理成圆形透明的图片,做圆形透明头像【微信头像】
  17. 《用于自动越野导航的实时语义映射》论文笔记
  18. 【SIP】Centos7搭建kamailio的SIP服务器实现网络电话
  19. [软件分享]速盘,一个新的摆渡网盘下载工具
  20. 【转载】Sqlserver使用Right函数从最右边向前截取固定长度字符串

热门文章

  1. 现在进行时的被动语态
  2. Java if、switch语句,break,case,类型转换、常量、赋值比较、标识符(2)
  3. Python_Python网络编程
  4. Elasticsearch Search API说明
  5. 明星为海地捐款 呼吁救援总动员
  6. 摆脱流量依赖,“心智营销”是玄学吗?
  7. windows工具箱
  8. Android自定义View——简单实现边缘凹凸电子票效果
  9. 远程视频会议系统/视频调度指挥平台/音视频通话系统EasyRTC在应急指挥领域中的应用
  10. 地铁区间——接触网(吊架和汇流排)布置