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

1. 背景

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

2. 实现方式

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

3. 代码

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;
    }
}

执行代码结果:
Springboot 批量增加redis中的数据,并批量设置过期时间_第1张图片
可以看到,普通遍历上传因为每次都需要发起一次请求,造成多次请求消耗,从而占用大量时间,而使用批量上传可以通过PipeLine管道命令来设置过期时间,只会有两次请求,时间上大幅度提升。

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

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

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

    //限流器
    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

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

你可能感兴趣的:(spring,boot,redis,后端)