当前位置: 首页 > news >正文

基于springboot跟redis实现的排行榜功能(实战)

概述

前段时间,做了一个世界杯竞猜积分排行榜。对世界杯64场球赛胜负平进行猜测,猜对+1分,错误+0分,一人一场只能猜一次。 1.展示前一百名列表。 2.展示个人排名(如:张三,您当前的排名106579)。 一.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,看个人喜好.

详细

详细

一、运行效果

image.png

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

二、实现过程

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

   : springboot-redis-rank   :     : defaultDataSource     : jdbc:mysql://localhost:3306/blue?serverTimezone=UTC     : root     : 123456   :     : : 127.0.0.1     :     : : : 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

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

2.新增默认排行数据

/*** 批量新增*/@Testpublic 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名(根据分数倒序)

/*** 获取排行列表*/@Testpublic 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.新增李四的分数

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

5.获取李四单人的排行

/*** 获取单个的排行*/@Testpublic 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.统计分数之间有多少人

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

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

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

8.使用加法操作分数

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

四.归纳

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

新增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);

三、项目结构图

image.png

四、补充

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

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

 

相关文章:

基于springboot跟redis实现的排行榜功能(实战)

概述 前段时间&#xff0c;做了一个世界杯竞猜积分排行榜。对世界杯64场球赛胜负平进行猜测&#xff0c;猜对1分&#xff0c;错误0分&#xff0c;一人一场只能猜一次。 1.展示前一百名列表。 2.展示个人排名(如&#xff1a;张三&#xff0c;您当前的排名106579)。 一.redis so…...

Mongodb常见操作命令

一、登录相关以及启动 启动服务mongodb&#xff1a; cd /usr/local/mongodb/bin ./mongod -f /data/mongodb/mongodb1.conf./mongod -f /data/mongodb/mongodb2.conf./mongod -f /data/mongodb/mongodb3.conf 登录mongodb数据库&#xff08;mongodb默认端口:27017&#xff0…...

springcloud-nacos简述

Spring Cloud alibaba: nacos服务注册中心&#xff0c;配置中心 服务注册中心 1.项目父工程添加springcloudalibaba依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><ve…...

【SpringSecurity】十二、集成JWT搭配Redis实现退出登录

文章目录 1、登出的实现思路2、集成Redis3、认证成功处理器4、退出成功处理器5、修改token校验过滤器6、调试 1、登出的实现思路 这是目前的token实现图&#xff1a; 因为JWT的无状态&#xff0c;服务端无法在使用过程中主动废止某个 token&#xff0c;或者更改 token 的权限…...

Docker进入容器出现bash: vi: command not found

&#x1f388;1 参考文档 docker基础容器中bash: vi: command not found问题解决 | 你邻座的怪同学-CSDN &#x1f50d;2 问题描述 在使用 Docker 容器时&#xff0c;有时候里边没有安装vim&#xff0c;敲vim命令时提示说&#xff1a;vim: command not found。 这个时候就需要…...

Linux_6_文件查找与打包压缩

目录 文件查找与打包压缩1文件查找1.1 locate1.2 find1.2.1 指定搜索目录层级1.2.2对每个目录先处理目录内的文件&#xff0c;再处理目录本身1.2.3根据文件名和inode查找1.2.4 根据属主、属组查找1.2.5根据文件类型查找1.2.6空文件或目录1.2.7组合条件1.2.8 排除日录1.2.9根据文…...

JavaWeb_LeadNews_Day9-Redis实现用户行为

JavaWeb_LeadNews_Day9-Redis实现用户行为 网关配置点赞阅读不喜欢关注收藏文章详情-行为数据回显来源Gitee 网关配置 nacos: leadnews-app-gateway # 用户行为微服务 - id: leadnews-behavioruri: lb://leadnews-behaviorpredicates:- Path/behavior/**filters:- StripPrefi…...

IntelliJ IDEA2021.3.1 使用 MybatisCodeHelperPro插件

一、 下载 下载破解后的 MybatisCodeHelperPro 的 V3.2.2版本 V3.2.2-CSDN 或者 V3.2.2-Gitee 二、 应用 将下载下来的Zip文件 放到电脑上的某个位置 (最好放在Idea 管理插件的 plugins 下) 然后自从搜索 Idea如何从磁盘中应用插件 三、激活 由于已经破解过了 但是还是需要激活…...

el-date-picker 等 点击无反应不回显问题解决

如上图&#xff0c;编辑回显正常&#xff0c;但是时间控件在拖动过程中时间不会跟随改变。 解决办法&#xff1a; <el-date-picker input"onInput()" ...><el-input input"onInput()" ...>js中onInput() {this.$forceUpdate();},...

Ansible学习笔记12

playbook&#xff1a; playbook&#xff08;剧本&#xff09;&#xff1a;是ansible用于配置、部署和管理被控节点的剧本&#xff0c;用于Ansible操作的编排。 使用的是yaml格式&#xff0c;&#xff08;saltstack、elk、docker、docker-compose、k8s都会使用到yaml格式。&am…...

sqlmap中文文档

这是 sqlmap -hh的翻译&#xff0c;后续可能会对参数进行详细的示例 sqlmap 普通选项 -h, --help # 显示基本帮助信息并退出 -hh # 详细帮助信息 --versino # 版本 -v # 日志详细级别 0-60&#xff1a;只显示python错误以及严重的信息。1&#xff1a;同时显示基本信…...

【C++模拟实现】vector的模拟实现

【C模拟实现】vector的模拟实现 目录 【C模拟实现】vector的模拟实现vector模拟实现的标准代码vector模拟实现中的要点insert和erase会涉及到迭代器失效的问题vector深度剖析关于模版template< class InputIterator >使用memcpy拷贝问题 作者&#xff1a;爱写代码的刚子 …...

go学习part21(3)redis连接池

连接池 1.介绍 每次使用数据就就建立链接再关闭可以&#xff0c;但是如果有大量客户端频繁请求连接&#xff0c;大量创建连接和关闭会非常耗费资源。 所以就建立一个连接池&#xff0c;里面存放几个不关闭的连接&#xff0c;谁要用就分配给谁。 说明:通过Golang 对 Redis操…...

乐理-笔记

乐理笔记整理 1、前言2、认识钢琴键盘及音名3、升降号、还原号4、如何区分同一音名的不同键&#xff1f;5、各类音符时值的关系6、歌曲拍号7、拍号的强弱规律8、歌曲速度&#xff08;BPM&#xff09;9、附点音符10、三连音12、唱名与简谱数字13、自然大调&#xff08;白键&…...

java八股文面试[数据库]——B树和B+树的区别

B树是一种树状数据结构&#xff0c;它能够存储数据、对其进行排序并允许以O(logn)的时间复杂度进行查找、顺序读取、插入和删除等操作。 1、B树的特性 B树中允许一个结点中包含多个key&#xff0c;可以是3个、4个、5个甚至更多&#xff0c;并不确定&#xff0c;需要看具体的实…...

2、Nginx 安装

文章目录 2、Nginx 安装2.1 官网下载2.2 安装 nginx2.2.1 第一步2.2.2 第二步2.2.3 第三步&#xff0c;安装 nginx2.2.4 第四步&#xff0c;修改防火漆规则 【尚硅谷】尚硅谷Nginx教程由浅入深 志不强者智不达&#xff1b;言不信者行不果。 2、Nginx 安装 2.1 官网下载 nginx…...

最适合 AI 的 Python Web 框架

迷途小书童的 Note 读完需要 4分钟 速读仅需 2 分钟 1 简介 本文将介绍 Gradio 库&#xff0c;它是 Python 的一个 web 框架&#xff0c;可以帮助我们快速构建交互式 AI 应用。我们将了解 Gradio 的应用场景、基本原理、功能介绍&#xff0c;并通过一个代码示例来演示如何使用 …...

算法通关村第十八关——回溯

回溯很大感觉就是多重递归&#xff0c;在递归的题目中&#xff0c;例如斐波那契数列&#xff0c;只需要考虑当前情况以及他的子情况。而在回溯中&#xff0c;要进行很多次递归&#xff0c;并且要对条件进行处理。 LeetCode257:给你一个二叉树的根节点root,按任意顺序&#xff…...

使用kafka还在依赖Zookeeper,kraft模式了解下

Kafka的Kraft模式 概述 ​ Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer&#xff0c;以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器…...

【100天精通Python】Day52:Python 数据分析_Numpy入门基础与数组操作

目录 1 NumPy 基础概述 1.1 NumPy的主要特点和功能 1.2 NumPy 安装和导入 2 Numpy 数组 2.1 创建NumPy数组 2.2 数组的形状和维度 2.3 数组的数据类型 2.4 访问和修改数组元素 3 数组操作 3.1 数组运算 3.2 数学函数 3.3 统计函数 4 数组形状操作 4.1 重塑数组形…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式&#xff0c;给定一个隐函数关系&#xff1a; F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 &#x1f9e0; 目标&#xff1a; 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...