Redis 常用配置实践

Redis 常用配置实践

这些是我在使用 redis 的过程中自己总结的一些实践,当然也参考了网上的一些文章和思想,用于一些日常的配置,主要解决以下问题:

1、序列化问题

这个应该在 java 领域用 redis 的人都知道,SpringBoot 在集成 redis 时,使用的 key value 序列化器为 jdk 序列化方式,会导致在使用 redis-cli 查看时,key 都是乱码,难以定位问题或获取值,不过也有可能是正常的,如果项目中只使用 RedisTemplate<String,String> 的话,原因是这种方式被单独重写了,序列化方式已经不再是 jdk 了

java 复制代码
    /**
     * RedisTemplate 序列化配置
     * 当 redisTemplate 没有被显示声明为 RedisTemplate<String, String> 时, key 和 value 会默认使用 jdk 的序列化方法
     * {@link org.springframework.data.redis.core.RedisTemplate#afterPropertiesSet()}
     * 此时如果使用 redis-cli 连接客户端查看,会发现 key 和 value 是乱码
     * <p>
     * RedisTemplate<String, String> 不会出现序列化乱码的原因是: 该类型被单独重写了
     * {@link org.springframework.data.redis.core.StringRedisTemplate}
     * <p>
     * 同时, value 不要为 Long 类型, Redis 为了节省内存会把没有超出 Integer 范围的 Long 数据转为 Integer 存储
     */
    @Bean
    public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

2、多项目共用 redis 集群

因为是 redis 集群,所以不再有单机 redis 16 个库的概念,一般情况下,可能公司只有几套 redis 环境,多个项目共用,导致项目测试完想清空数据再次测试的话,难以处理之前在 redis 中的旧数据,最容易想到的解决方式肯定就是每个项目的缓存数据用不同的前缀

那么最方便的当然是自定义序列化器,重写 key 的序列化和反序列化方式,使每次存和读取的时候都自动加上前缀

java 复制代码
@Configuration
public class RedisConfig {

    @Autowired
    private PrefixRedisKeySerializer redisKeySerializer;

    @Bean
    public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(redisKeySerializer);
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setHashKeySerializer(redisKeySerializer);
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(redisKeySerializer);
        return template;
    }

}
java 复制代码
@Component("redisKeySerializer")
public class PrefixRedisKeySerializer extends StringRedisSerializer {

    private static final String RedisKeyPrefix = "prefix_";

    @Override
    public byte[] serialize(String s) {
        if (s == null) {
            return new byte[0];
        }
        String realKey = RedisKeyPrefix + s;
        return realKey.getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public String deserialize(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        String s = new String(bytes, StandardCharsets.UTF_8);
        if (StringUtil.isNullOrEmpty(s)) {
            return s;
        }
        int index = s.indexOf(RedisKeyPrefix);
        if (index != -1) {
            return s.substring(RedisKeyPrefix.length());
        }
        return s;
    }

}

当然也可以使用 @Value 注解这种,把前缀放在配置文件里~

3、项目启动后在 redis 存放热点数据

有一些数据,我们知道它是热点数据,或者知道一定会用到,可能会希望在项目启动后就把它存入 redis 中,一种是说从某个表查询然后存入 redis,另一种就是明确知道其 key 和 value,希望启动时候将其存入 redis

java 复制代码
@Component
public class RedisHotKeyRunner implements ApplicationRunner {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ParamDao paramDao;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        IntStream.rangeClosed(1, 15).forEach(i -> {
            Param param = new Param();
            param.setId(i);
            param.setCode("key_" + i);
            param.setValue("value_" + i);
            param.setType("type_" + i);
            paramDao.save(param);
        });

        redisTemplate.opsForValue().set("jzsj", "2025-06-16");
        redisTemplate.opsForValue().set("username", "zhangsan");

        IntStream.rangeClosed(0, 14).forEach(i -> {
            redisTemplate.opsForSet().add("user_set_" + i, "set");
        });

        // 这里只是从数据库查询并测试插入,实际业务自行定义到底存什么类型的数据
        List<Param> all = paramDao.findAll();
        all.forEach(param -> {
            redisTemplate.opsForHash().put("param", param.getCode(), param.getValue());
        });

    }

}

需要注意的地方是,如果设置了统一前缀,那么 hash 操作的 field 也会加上这个前缀哦~

bash 复制代码
127.0.0.1:6379> hgetall esjdjg_param
 1) "prefix_key_1"
 2) "\"value_1\""
 3) "prefix_key_2"
 4) "\"value_2\""
 5) "prefix_key_3"
 6) "\"value_3\""
 7) "prefix_key_4"
 8) "\"value_4\""
 ......
相关推荐
Logintern0921 小时前
理解MySQL数据库的“事务与锁”
数据库·mysql
朱容zr33313321 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化
麻瓜code21 小时前
【Redis 】数据类型、持久化与过期删除
数据库·redis·缓存
空杆推不起1 天前
穿透 Flink CDC 表层用法:数据库日志捕获机制、Flink Source 运行时、端到端一致性底层原理详解
大数据·数据库·flink
朱容zr3331331 天前
请解释“回表”的概念。
java·前端·数据库
☆凡尘清心☆1 天前
CentOS Stream 9 编译安装 Redis 7.2.7 完整版详细步骤
linux·redis·centos
大黄说说1 天前
EF Core 避坑指南:查询慢、循环查询、并发更新问题如何解决
java·服务器·数据库
城管不管1 天前
重生——第五次面试2026.8.1一面
java·数据库·后端·ai·面试·职场和发展·agent
ocean'1 天前
防火墙策略路由
linux·服务器·数据库
晚安code1 天前
RocketMQ 延迟消息实战:延迟双删策略解决 Redis 缓存一致性
redis·rocketmq