说明:本文介绍针对一个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 {@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Overridepublic 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 {@Autowiredprivate RedisServiceImpl redisService;@Testpublic 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实现)
@Overridepublic 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);// 拼接分段keyString subKey = key + "_" + i;// 存储分段数据setString(subKey, chunkValue);// 将分段key添加到集合subKeys.add(subKey);}// 分段key添加到集合setList(key, subKeys);}
(添加一个集合到Redis)
@Overridepublic void setList(String key, List value) {redisTemplate.opsForList().rightPushAll(key, value);}
启动,测试
@Testpublic void test2() {String key = "content";String value = "这是一段分非常大非常大的字符串…………………………非常大";redisService.setStrSub(key, value, 5);}
查看Redis
然后,要取数据,也很简单;
(缓存接口)
/*** 获取字符串(分段)* @param key* @return*/String getStrSub(String key);
(Redis实现)
@Overridepublic 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);}// 如果没有数据,返回nullreturn "".contentEquals(stringBuilder) ? null : stringBuilder.toString();}
(Redis获取一个List)
@Overridepublic List getList(String key) {return redisTemplate.opsForList().range(key, 0, -1);}
(使用)
@Testpublic void test3() {String content = redisService.getStrSub("content");System.out.println(content);}
(打印)
总结
本文介绍了Redis分段存储一个大键值对(String)的一种方式,看下来,实现并不复杂。使用上也可以很方便,可以考虑把分段的存取和普通的存取都兼容起来,这样对于使用者,只需要加一个参数(分段大小)。