SpringBoot集成Redis业务功能 02、定时任务+Redis删除特定前缀key的优雅实现

简介: SpringBoot集成Redis业务功能 02、定时任务+Redis删除特定前缀key的优雅实现

方案思路


之前重置玩家每日积分3次是采用redis来实现的,每位玩家在进行重置积分操作时,就会进行存储reids的键值对,key时拼接玩家uid的字符串,value则是每日次数,在set时是设置24小时也就是1天过期。


基于此方案上,我想了想那么就使用定时任务+批量删除redis前缀key来实现比较合适。


其中的批量删除redis的前缀key有两种方案实现:


直接使用keys命令来进行匹配所有的key,然后进行批量delete删除(不推荐)。【问题:数据量达到几百万,keys这个指令就会导致 Redis 服务卡顿,因为 Redis 是单线程程序,顺序执行所有指令,其它指令必须等到当前的 keys 指令执行完了才可以继续 。】

使用scan渐进式遍历获取到所有的key,实现keys的效果,需要进行多次scan**(推荐)**。【好处:采用渐进式遍历的方式来解决keys命令可能带来的阻塞问题,每次scan命令的时间复杂度是 O(1) ,但是要真正实现keys的功能,需要执行多次scan。】

redis+lua脚本(暂未使用)。

当前实现方案中就是使用的scan渐进式遍历来进行获取。


实现方案


批量删除redis的key


关于SpringBoot如何集成Redis见:SpringBoot整合篇 04、Springboot整合Redis


在下面代码中我们使用到了MultiKeyCommands,这个类是jedis里的,那么我们就需要将redis启动器中的lettuce替换为jedis,如下来进行排除依赖并添加jedis依赖:


<!--redis配置-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--  排除lettuce,使用jedis      -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <scope>compile</scope>
</dependency>



下面scan方法已经封装好了,使用方式:调用方法,直接传入要匹配的前缀key即可使用scan返回所有匹配到的key。


一轮是获取1000个的。
/**
 * redis工具类
 */
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache {
   /**
     *
     * @param key 要匹配的key前缀
     * @return 匹配到的批量key值
     */
    public Set<String> scan(String key) {
        return (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            HashSet<String> keys = new HashSet<>();
            JedisCommands commands = (JedisCommands) connection.getNativeConnection();
            MultiKeyCommands multiKeyCommands = (MultiKeyCommands) commands;
            //组装scan请求参数(匹配内容+请求数量)
            ScanParams scanParams = new ScanParams();
            scanParams.match("*" + key + "*");
            scanParams.count(1000);
            //执行scan命令(批量去获取)
            ScanResult<String> scan = multiKeyCommands.scan("0", scanParams);
            while (scan.getCursor() != null) {
                keys.addAll(scan.getResult());
                if ("0".equals(scan.getCursor())) {
                    break;
                }
                scan = multiKeyCommands.scan(scan.getCursor(), scanParams);
            }
            return keys;
        });
    }
}


定时任务


定时任务使用Spring给我们提供的,按照如下进行配置即可:


1、在启动器上开启定时任务注解


@EnableScheduling //开启定时任务


2、注册Bean对象,在指定的方法上添加定时任务注解


对于定时任务的cron表示式可用在线工具生成:cron表达式生成工具


生成的是7位,而@Scheduled中的cron要求是6位,我们只需要把最后一位表示年的去年即可。

package com.chuangmeng.horserace.tasks;


import com.chuangmeng.horserace.constant.RedisKeyConstant;
import com.chuangmeng.horserace.utils.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.util.Set;
@Component
@Slf4j
public class PlayerTask {
    @Autowired
    private RedisCache redisCache;
    /**
     * 每天晚上12点重置玩家积分
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void resetPlayerIntegral() {
        String key = "xxx";
        Set<String> keys = redisCache.scan(key);
        log.info("相关重置积分的key为:" + keys);
        if (!ObjectUtils.isEmpty(keys)) {
            redisCache.deleteObject(keys);
            log.info("重置玩家积分完成!");
        }
    }
}



完成重置操作也很简单,就是调用下scan()方法,然后拿到所有的key,执行删除命令就好。


测试

使用redis手动来去进行匹配前缀key:


# 方式一:使用keys来进行匹配
keys "chuangmeng:horserace:resetimtegral:*"
# 方式二:使用scan来进行渐进式获取,第一次设置游标为0,会响应过来两个数据,一个是下一次你要进行遍历开始的游标,以及一组匹配的数据。若是下一组游标为0,那么就无需进行scan获取了,已经获取了全部
scan 0 match "chuangmeng:horserace:resetimtegral:*"
scan 17 match "chuangmeng:horserace:resetimtegral:*"
# 删除key
del chuangmeng:horserace:resetimtegral:3334322232  chuangmeng:horserace:resetimtegral:12364322232


对于程序的话我们测试可以设置个1分钟定时任务或者直接在test中调用方法测试即可!

相关文章
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
993 2
|
JSON 分布式计算 大数据
springboot项目集成大数据第三方dolphinscheduler调度器
springboot项目集成大数据第三方dolphinscheduler调度器
944 3
|
缓存 前端开发 Java
SpringBoot 实现动态菜单功能完整指南
本文介绍了一个动态菜单系统的实现方案,涵盖数据库设计、SpringBoot后端实现、Vue前端展示及权限控制等内容,适用于中后台系统的权限管理。
1355 1
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
1144 0
第07课:Spring Boot集成Thymeleaf模板引擎
|
存储 NoSQL Redis
采用Redis的Bitmaps实现类似Github连续提交状态的功能。
在现实世界的应用开发中,实现类似于Github提交跟踪系统时,还可能需要考虑用户时区、闰年等日期相关的边界条件,以及辅助数据的存储和查询优化,例如对活跃用户的即时查询和统计等。不过这些都可以在Bitmaps的基础功能之上通过额外的代码逻辑来实现。
321 0
|
分布式计算 大数据 Java
springboot项目集成大数据第三方dolphinscheduler调度器 执行/停止任务
springboot项目集成大数据第三方dolphinscheduler调度器 执行/停止任务
425 0
|
存储 人工智能 Java
Springboot集成AI Springboot3 集成阿里云百炼大模型CosyVoice2 实现Ai克隆语音(未持久化存储)
本项目基于Spring Boot 3.5.3与Java 17,集成阿里云百炼大模型CosyVoice2实现音色克隆与语音合成。内容涵盖项目搭建、音色创建、音频合成、音色管理等功能,适用于希望快速掌握Spring Boot集成语音AI技术的开发者。需提前注册阿里云并获取API Key。
|
NoSQL Java Redis
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
1162 0
|
NoSQL Java Redis
SpringBoot集成Redis
SpringBoot集成Redis
832 0