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

Spring Data Redis 实战避坑:搞定序列化乱码与 Hash 结构存储

Spring Data Redis 实战避坑:搞定序列化乱码与 Hash 结构存储

在 Java 后端开发中,Redis 几乎是高并发场景下的标配。虽然 Redis 自带的命令行客户端redis-cli功能强大,但在实际项目中,我们更多是通过 Java 客户端来与 Redis 进行交互。

下面将讲述最容易踩到的“序列化乱码”深坑,以及如何优雅地使用 Hash 结构存储对象。

一、 从 Jedis 到 Spring Data Redis

在 Java 生态中,操作 Redis 的主流客户端有 Jedis 和 Lettuce。早期的 Jedis 实例是线程不安全的,为了避免频繁创建和销毁 TCP 连接带来的性能损耗,我们通常需要引入 Jedis 连接池(JedisPool)。

而 Spring Data Redis 作为 Spring 家族的一员,对上述客户端进行了高度封装。它提供了统一的 API ——RedisTemplate,不仅屏蔽了底层客户端的差异,还支持 Redis 哨兵、集群以及响应式编程。

在 Spring Boot 项目中,我们只需要引入spring-boot-starter-data-redis和连接池依赖commons-pool2,就可以在 YAML 中配置好 Redis 的连接信息,通过@Autowired直接注入RedisTemplate来使用。

二、 避坑指南:序列化导致的“乱码”危机

RedisTemplate虽然好用,但很多新手在第一次使用时都会遇到一个诡异的现象:明明在 Java 代码中设置了一个 Key,但在 Redis 图形化客户端中查看时,Key 前面却多了一长串看不懂的乱码,或者存入的 Value 变成了一串二进制字节。

这是因为RedisTemplate默认采用了 JDK 序列化(JdkSerializationRedisSerializer)。这种序列化方式虽然能保留对象的完整结构,但可读性极差,且占用的内存空间较大。

为了解决这个问题,我们需要自定义RedisTemplate的序列化策略。通常的最佳实践是:Key 采用 String 序列化,Value 采用 JSON 序列化。

我们可以通过以下配置类,将序列化方式替换为Jackson2JsonRedisSerializer

@ConfigurationpublicclassRedisConfig{@Bean@SuppressWarnings({"rawtypes","unchecked"})publicRedisTemplate<String,Object>redisTemplate(RedisConnectionFactoryfactory){RedisTemplate<String,Object>template=newRedisTemplate<>();template.setConnectionFactory(factory);// 1. 配置 Value 的 JSON 序列化Jackson2JsonRedisSerializer<Object>jackson2JsonRedisSerializer=newJackson2JsonRedisSerializer<>(Object.class);ObjectMapperom=newObjectMapper();om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(om.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// 2. 配置 Key 的 String 序列化StringRedisSerializerstringRedisSerializer=newStringRedisSerializer();// 3. 注入序列化器template.setKeySerializer(stringRedisSerializer);template.setHashKeySerializer(stringRedisSerializer);template.setValueSerializer(jackson2JsonRedisSerializer);template.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();returntemplate;}}

经过这番配置,你再存入数据时,Key 就是清清爽爽的字符串,而 Value 也会变成可读性极强的 JSON 格式。

三、 另一种选择:StringRedisTemplate

如果你觉得自定义序列化配置太麻烦,或者你的业务场景中缓存的大多是简单的字符串(比如 Token、验证码),Spring Boot 其实还提供了一个开箱即用的StringRedisTemplate

它的 Key 和 Value 默认都采用 String 序列化。如果你需要存储 Java 对象,只需要在写入前手动将对象序列化为 JSON 字符串,读取时再手动反序列化即可:

个人在学习中常用此方法

@AutowiredprivateStringRedisTemplatestringRedisTemplate;@AutowiredprivateObjectMapperobjectMapper;// 存入对象publicvoidsaveUser(Useruser)throwsException{Stringjson=objectMapper.writeValueAsString(user);stringRedisTemplate.opsForValue().set("user:"+user.getId(),json,30,TimeUnit.MINUTES);}// 取出对象publicUsergetUser(Stringid)throwsException{Stringjson=stringRedisTemplate.opsForValue().get("user:"+id);returnjson!=null?objectMapper.readValue(json,User.class):null;}
四、 Redis Hash 与 Java 代码的映射实战

除了基础的 String 类型,Redis 的 Hash 结构非常适合用来存储对象(比如用户信息、商品信息)。它允许我们将一个对象的多个字段拆分开来存储,而不是像 String 那样必须把整个对象序列化成一个大 JSON。

在 Redis 命令行中,我们使用HSETHGET来操作 Hash。而在 Java 的RedisTemplate中,这些操作被封装在了HashOperations接口里。

以下是 Redis 命令与 Java API 的对照实战:

操作场景Redis 命令Java (HashOperations)
添加/更新字段HSET key field valueput(key, hashKey, value)
获取单个字段HGET key fieldget(key, hashKey)
获取所有字段HGETALL keyentries(key)
删除字段HDEL key fielddelete(key, hashKey)

代码示例:

@AutowiredprivateRedisTemplate<String,Object>redisTemplate;publicvoidtestHash(){// 1. 获取 Hash 操作对象HashOperations<String,Object,Object>opsForHash=redisTemplate.opsForHash();// 2. 存入用户信息 (相当于 HSET user:1001 name Tom)opsForHash.put("user:1001","name","Tom");opsForHash.put("user:1001","age",25);// 3. 获取单个字段 (相当于 HGET user:1001 name)Objectname=opsForHash.get("user:1001","name");System.out.println("用户名: "+name);// 4. 获取所有字段 (相当于 HGETALL user:1001)Map<Object,Object>entries=opsForHash.entries("user:1001");System.out.println("用户所有信息: "+entries);}
五、 总结
  • 如果你需要存储复杂的对象且希望 Redis 中数据可读,推荐使用自定义序列化器的RedisTemplate
  • 如果你只是存储简单的字符串,StringRedisTemplate配合手动序列化是更轻量级的选择。
  • 在操作 Hash 结构时,记住HSET对应putHGETALL对应entries,就能轻松搞定对象字段的增删改查。
http://www.cnnetsun.cn/news/2515607.html

相关文章:

  • pygame库
  • 矿用电机车运行参数保护系统,让井下轨道运输更安全
  • 主产区安全整改深化 行业加速洗牌(5 月 21 日)
  • 3分钟解锁:JoyCon-Driver让你的Switch手柄在Windows上完美运行
  • Windows右键菜单终极优化指南:如何用ContextMenuManager让右键菜单快速响应
  • NifSkope:零门槛编辑《上古卷轴》与《辐射》游戏模型的完整指南
  • 好用的长沙装修设计值得选的服务商
  • 百考通:AI一键生成论文降重与去AI痕迹,提供双重优化保障,让学术成果更合规
  • 【NotebookLM关键词提取黄金标准】:基于127份实测文档验证的4级置信度评估体系
  • 书匠策AI:论文降重降AIGC一键搞定,这个宝藏工具你还不知道?
  • 桥梁损伤目标检测数据集分享(适用于YOLO系列深度学习分类检测任务)
  • 3步搞定RK3588开发板Ubuntu系统部署:新手也能轻松上手
  • 5步彻底解决FanControl配置崩溃:从诊断到修复的完整指南
  • 如何彻底解决ThinkPad风扇噪音问题:TPFanCtrl2完整实战指南
  • 告别vcvars.bat!在VS2022中创建一键配置编译环境的快捷方式(支持所有终端)
  • 喜马拉雅音频下载终极指南:免费构建个人音频资源库
  • BlindWaterMark盲水印技术实战指南:Python实现版权保护与数字取证高效方案
  • AI能力跃迁与分阶段发布机制解析
  • ARM AArch32内存管理:TTBCR2与TTBR寄存器详解
  • LVGL样式进阶:别再只改颜色了!手把手教你定制lv_switch的动画和lv_btn的按压反馈
  • 压路机远程监控运维管理平台方案
  • 如何永久守护你的微信数字记忆:一份完整的个人数据自主指南
  • AI重绘科技女性史:史料驱动的历史人物可视化方法论
  • Go语言WebSocket实时通信实战
  • 如何快速部署FreeACS:开源TR-069自动配置服务器完整指南
  • Verilator仿真保姆级避坑指南:从安装最新版到用GTKWave看波形的完整流程
  • 电容选型频率逻辑:从阻抗曲线到高频去耦布局实战
  • 仅限前500名开发者获取:DeepSeek事实校验黄金清单(含17个自动检测脚本+3类可信度评分模板)
  • 如何高效获取和管理音乐歌词:163MusicLyrics完整使用指南
  • FSearch技术深度解析:如何用C语言和GTK3实现毫秒级文件搜索