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

如何分段存储Redis键值对

说明:本文介绍针对一个value过长的键值对,如何分段存储;

场景

当我们需要存入一个String类型的键值对到Redis中,如下:

(缓存接口)

public interface CacheService {

    /**
     * 添加一个字符串键值对
     * @param key 键
     * @param value 值
     */
    void setString(String key, String value);
}

(Redis实现)

import com.hezy.service.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RedisServiceImpl implements CacheService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    @Override
    public void setString(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }
}

(使用)

import com.hezy.service.impl.RedisServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class RedisServiceImplTest {

    @Autowired
    private RedisServiceImpl redisService;

    @Test
    public void test1() {
        String key = "content";
        String value = "这是一段分非常大非常大的字符串…………………………非常大";
        redisService.setString(key, value);
    }
}

(查看Redis)

在这里插入图片描述

有时候,我们存入的字符串可能过长,过大,有可能来自于一个大对象的序列化。这时候存入的key-value,会造成value过大,会触发一些预警。

可以采用我下面这种分段存储的方法。

优化

思路:将字符串分段,每一段生成一个key,然后将这些分段key再用Redis的List类型存储;获取时就先获取这些分段key,再循环去get对应的字符串,拼接起来就是完整的字符串。

如下:分段存,增加一个参数,设置每段字符串的长度

(缓存接口)

    /**
     * 分段存储
     * @param key 键
     * @param value 值
     * @param chunkSize 每个分段大小
     */
    void setStrSub(String key, String value, int chunkSize);

(Redis实现)

    @Override
    public void setStrSub(String key, String value, int chunkSize) {
        // 将value,按照length,分成多个部分
        int totalChunks = (int) Math.ceil((double) value.length() / chunkSize);
        // 定义一个分段数据key集合
        List<String> subKeys = new ArrayList<>(totalChunks);
        // 将字符串分成多段
        for (int i = 0; i < totalChunks; i++) {
            // 计算分段起止位置
            int startIndex = i * chunkSize;
            int endIndex = Math.min(startIndex + chunkSize, value.length());
            // 获取对应分段数据
            String chunkValue = value.substring(startIndex, endIndex);
            // 拼接分段key
            String subKey = key + "_" + i;
            // 存储分段数据
            setString(subKey, chunkValue);
            // 将分段key添加到集合
            subKeys.add(subKey);
        }
        // 分段key添加到集合
        setList(key, subKeys);
    }

(添加一个集合到Redis)

    @Override
    public void setList(String key, List value) {
        redisTemplate.opsForList().rightPushAll(key, value);
    }

启动,测试

    @Test
    public void test2() {
        String key = "content";
        String value = "这是一段分非常大非常大的字符串…………………………非常大";
        redisService.setStrSub(key, value, 5);
    }

查看Redis

在这里插入图片描述

在这里插入图片描述

然后,要取数据,也很简单;

(缓存接口)

    /**
     * 获取字符串(分段)
     * @param key
     * @return
     */
    String getStrSub(String key);

(Redis实现)

    @Override
    public String getStrSub(String key) {
        // 先把分段key获取出来
        List<String> list = getList(key);
        // 字符串拼接,用StringBuilder,线程安全
        StringBuilder stringBuilder = new StringBuilder();
        for (String subKey : list) {
            String subValue = getString(subKey);
            // 这里要跳过null,不然最后输出会把null转为字符串
            if (subValue == null) {
                continue;
            }
            stringBuilder.append(subValue);
        }
        // 如果没有数据,返回null
        return "".contentEquals(stringBuilder) ? null : stringBuilder.toString();
    }

(Redis获取一个List)

    @Override
    public List getList(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

(使用)

    @Test
    public void test3() {
        String content = redisService.getStrSub("content");
        System.out.println(content);
    }

(打印)

在这里插入图片描述

总结

本文介绍了Redis分段存储一个大键值对(String)的一种方式,看下来,实现并不复杂。使用上也可以很方便,可以考虑把分段的存取和普通的存取都兼容起来,这样对于使用者,只需要加一个参数(分段大小)。


http://www.kler.cn/a/419399.html

相关文章:

  • 活着就好20241203
  • WRF-Chem模式安装、环境配置、原理、调试、运行方法;数据准备及相关参数设置方法
  • 一万台服务器用saltstack还是ansible?
  • LWIP和FATFS 实现 FTP 服务端
  • Django Auth的基本使用
  • 泷羽sec学习打卡-shell命令5
  • 智慧银行反欺诈大数据管控平台方案(二)
  • windows C#-为类或结构定义值相等性(上)
  • 网络原理-初识
  • 解密开源大模型如何实现本地化部署并基于本地的知识库进行应用
  • Java基础面试题11:简述System.gc()和Runtime.gc()的作用?
  • 一些面试问题的深入与思考
  • 国际网络安全趋势
  • git push使用
  • 探索Linux的目录结构:深入理解文件系统的组织
  • mongodb配置ssl连接
  • 详解Qt PDF 之 QPdfDocument与 QPdfView 打开与显示pdf
  • 如何在 Debian 7 上设置 Apache 虚拟主机
  • 时频转换 | Matlab基于S变换S-transform一维数据转二维图像方法
  • node == RabbitMQ入门教程
  • 手机控制载货汽车一键启动无钥匙进入广泛应用
  • 综合实验——用户远程登陆并更改文件
  • 网络七层杀伤链
  • 网络安全-夜神模拟器如何通过虚拟机的Burp Suite代理应用程序接口
  • python学习笔记9-零散知识点
  • vue3 路由跳转携带参数以及其他页面接收参数