Springboot 批量增加redis中的数据,并批量设置过期时间

1. 背景

一个功能需要一次性解析大量数据放到 Redis 中缓存,并且每个 key 都需要设置过期时间,但是 Redis 本身命令不支持批量设置过期时间,RedisTemplate 中也没有相关的方法。

2. 实现方式

1. RedisTemplate 使用 redisTemplate.opsForValue().multiSet() 来实现批量插入数据
2. RedisTemplate使用PipeLine管道命令来批量修改过期时间

3. 代码

bash 复制代码
package com.insupro.flexibleServerJ.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author luoqifeng
 */
@Slf4j
@RestController
@RequestMapping("/api")
public class RedisDemo002 {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @RequestMapping("testRedisMultiSet")
    public Object testRedisMultiSet() {
        Map<String, String> keysAndValues = new HashMap<>();
        // 模拟数据
        for (int i=0; i < 100; i++){
            String redisKey = "testKey_"+i;
            String value = "testValue_"+i;
            keysAndValues.put(redisKey, value);
        }

        if (!keysAndValues.isEmpty()){
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("正常遍历上传计时");

            for (String key: keysAndValues.keySet()){
                redisTemplate.opsForValue().set(key, keysAndValues.get(key), 20, TimeUnit.SECONDS);
            }
            stopWatch.stop();

            // 以下是批量上传方式
            stopWatch.start("批量上传redis计时");
            redisTemplate.opsForValue().multiSet(keysAndValues);
            // 设置过期值
            stopWatch.stop();
            stopWatch.start("批量设置过期时间");

            redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                keysAndValues.forEach((key, vaul) -> {
                    connection.expire(key.getBytes(), 20);
                });
                return null;
            });
            stopWatch.stop();
            log.info("执行耗时:{}", stopWatch.prettyPrint());
        }
        return  null;
    }
}

执行代码结果:

可以看到,普通遍历上传因为每次都需要发起一次请求,造成多次请求消耗,从而占用大量时间,而使用批量上传可以通过PipeLine管道命令来设置过期时间,只会有两次请求,时间上大幅度提升。

疑问:为什么不直接使用管道上传并设置过期时间呢?

回答: 当然可以,我只是做个演示,具体实现需要根据业务需求做相应的操作。

例如:通过管道实现简单限流思想逻辑

bash 复制代码
    //限流器
    public void currentLimiter(){
        List<Object> objects = redisTemplate.executePipelined(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                connection.openPipeline();
                //key
                String key = "userId:mucontroller:save";
                //当前时间
                Long time = System.currentTimeMillis();
                //限定1min中内的请求
                Long period = 1L;
                //请求记录
                connection.zSetCommands().zAdd(key.getBytes(), time, key.getBytes());
                //删除1min之外的请求
                connection.zSetCommands().zRemRangeByScore(key.getBytes(), 0.0, Double.valueOf(time - period * 1000));
                //统计1min内的记录次数
                Long size = connection.zSetCommands().zCard(key.getBytes());
                //设置过期时间
                connection.expire(key.getBytes(), period);
                if(size > 3){
                    return 0L;
                } else {
                    return 1L;
                }
            }
        });
    }

end

以上都是实例,需要根据自行业务逻辑进行修改封装,以确保程序的健壮性

相关推荐
一只叫煤球的猫5 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9655 小时前
tcp/ip 中的多路复用
后端
bobz9655 小时前
tls ingress 简单记录
后端
你的人类朋友6 小时前
什么是OpenSSL
后端·安全·程序员
bobz9657 小时前
mcp 直接操作浏览器
后端
前端小张同学9 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook9 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康10 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在10 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net
文心快码BaiduComate10 小时前
文心快码入选2025服贸会“数智影响力”先锋案例
前端·后端·程序员