当前位置:首页 > 文章列表 > 数据库 > Redis > Redis Hash与JSON字符串存储对象的选择边界

Redis Hash与JSON字符串存储对象的选择边界

来源:17golang原创 2026-09-20 11:44:11 0浏览 收藏

我在给用户资料做缓存时,最容易踩的坑不是命令不会用,而是把“对象”三个字直接等同于一种 Redis 结构。需要按字段改昵称、按字段读状态时,Hash 很顺手;只想把一份已经序列化好的响应整体放进去,普通字符串 JSON 更直接;如果业务要求在 JSON 文档内部按路径修改,才值得评估 RedisJSON。

官方地址:https://redis.io/

要点速览
  • Hash 把对象字段拆成 Redis field,适合局部读写;但 HGETALL 会随字段数增长。
  • 字符串 JSON 的边界清晰,适合整对象 SET/GET;局部改一个字段要重新序列化并覆盖整值。
  • RedisJSON 支持 JSONPath 级访问与更新,但部署、客户端和运维能力要先确认。
  • EXPIRE 作用在 key 上,HSET 不会清掉已有 key 的过期时间;字段级 TTL 要另看 Redis 版本能力。

先把“对象怎么被使用”说清楚

同一个 User 对象,如果每次请求都读取全部字段,Hash 和字符串 JSON 都能完成任务;如果只改 status,Hash 可以直接 HSET,而字符串 JSON 通常要 GET、反序列化、修改、再 SET。这个差异会随着对象大小和写入频率放大,所以选型应先看访问粒度。

需求优先方案要留意的边界
字段稳定、经常局部读写Redis Hash全量读取使用 HGETALL,字段多时要控制对象大小
整对象缓存、序列化结果直接透传字符串 JSON局部修改需要整值重写,注意并发覆盖
需要 JSONPath 局部更新RedisJSON确认模块、客户端和集群运维支持

Hash:把字段级操作放到缓存层

Redis 官方把 Hash 描述为 field-value 集合。典型的 key 可以是 user:42,字段是 namestatusupdated_at。在 Go 客户端中,保存对象时可以显式列出允许进入缓存的字段,避免把数据库内部字段无意暴露出去。

package main

import (
    "context"
    "time"

    "github.com/redis/go-redis/v9"
)

func saveUserHash(ctx context.Context, rdb *redis.Client) error {
    // Hash 只保存缓存契约中的字段,便于按字段修改和排查。
    key := "user:42"
    if err := rdb.HSet(ctx, key,
        "name", "Lin",
        "status", "active",
        "updated_at", "2026-09-20T10:00:00+08:00",
    ).Err(); err != nil {
        return err
    }

    // 过期时间挂在 key 上;HSET 修改字段不会自动清除已有 TTL。
    return rdb.Expire(ctx, key, 30*time.Minute).Err()
}
Redis Hash把用户对象拆成字段并连接到HSET、HGET和key级过期边界的静态说明图
图1:Redis Hash 结构说明图,展示对象字段、字段级读写命令与 key 级过期之间的静态关系,不是运行截图。

读取单个状态时用 HGet,只取多个已知字段时用 HMGet;只有确实需要组装整个对象时再用 HGetAll。后者的复杂度会随字段数量增加,不能因为对象看起来小就默认全量读取。

字符串 JSON:用整值缓存换取简单边界

如果上游接口本来就产出 JSON,普通字符串方案通常更容易迁移:应用把结构体编码成 JSON,Redis 只负责保存和返回字节。Redis 不理解其中的字段,因此也不会替你完成 JSONPath 查询或字段级合并。

package main

import (
    "context"
    "encoding/json"
    "time"

    "github.com/redis/go-redis/v9"
)

type UserCache struct {
    Name   string `json:"name"`
    Status string `json:"status"`
}

func saveUserJSON(ctx context.Context, rdb *redis.Client, user UserCache) error {
    // 字符串 JSON 适合整对象缓存,写入前由应用负责序列化。
    payload, err := json.Marshal(user)
    if err != nil {
        return err
    }
    // SET 的 EX 让写入和 key 级 TTL 在一次命令中完成。
    return rdb.Set(ctx, "user:42", payload, 30*time.Minute).Err()
}

上面的示例还需要在导入区加入 encoding/json。这里故意把序列化责任留在应用层:字段变更时要考虑旧缓存兼容,多个写请求同时更新不同字段时也要避免“后写覆盖先写”的整值丢失。

RedisJSON:只有文档路径更新才值得引入

Redis 官方 JSON 文档提供 JSON.SETJSON.GET 等命令,并支持路径级访问。它和“Redis 字符串里放一段 JSON”不是一回事:后者只是应用保存的字节,前者需要对应的 RedisJSON 能力与客户端支持。

# RedisJSON 示例:只更新文档中的 status 路径,不覆盖其他字段
JSON.SET user:42 $.status '"active"'
# 读取单个路径,返回值形态取决于客户端的 JSON 命令封装
JSON.GET user:42 $.status

如果线上环境只有基础 Redis 命令,不能把这段命令当成普通 SET 的替代品。先确认服务形态、模块加载方式、集群兼容性和 Go 客户端 API,再决定是否让缓存模型依赖它。

Redis Hash、字符串JSON与RedisJSON围绕更新粒度、读取方式和部署能力的选择关系说明图
图2:三种对象存储方式的选择说明图,连接访问粒度、序列化边界、JSON路径更新和部署能力,不是运行截图。

过期和并发是最后的落点

最稳妥的 key 设计通常先统一过期策略:Hash 与字符串 JSON 都可以对 key 使用 EXPIRE,字符串 JSON 也可在 SET 时带 EX。如果字段需要不同生命周期,先确认目标 Redis 版本是否提供字段级过期命令,再评估它是否值得增加客户端和运维复杂度。

  • 局部字段更新多、字段集合相对稳定:优先 Hash,并限制 HGETALL 的对象大小。
  • 整对象读写多、缓存内容直接作为接口响应:优先字符串 JSON,配合版本字段或乐观覆盖策略。
  • 必须按 JSONPath 改嵌套字段或数组:评估 RedisJSON,同时把模块能力写进部署清单。
  • 多个写者会同时改同一对象:不要只靠“最后一次 SET”,必要时使用事务、版本号或重新设计 key。

我的经验是先选能覆盖主要访问路径、依赖最少的结构:Hash 和字符串 JSON 往往已经够用。只有“必须原子更新嵌套文档”这个需求真实存在时,再把 RedisJSON 纳入方案。这样迁移和故障排查时,数据结构本身不会成为额外的隐藏前提。

相关问题

Hash 能不能保存嵌套对象?

可以把嵌套对象单独序列化成某个 field 的字符串,但 Redis 不会理解其中的层级;如果需要路径级操作,应重新评估 RedisJSON 或拆分 key。

HSET 之后还需要重新 EXPIRE 吗?

已有 key 的 HSET 不会清掉 key 的 TTL,但首次创建 key 或采用不同生命周期策略时,仍应明确设置并检查 TTL。

JSON 字符串一定比 Hash 占空间少吗?

不一定。空间取决于字段名重复、对象大小、编码方式和 Redis 内部实现,不能只凭结构名称下结论,应在代表性数据上测量。

什么时候不该把对象放 Redis?

当数据需要复杂查询、强一致持久化或长期审计时,Redis 更适合作为缓存或加速层,主数据仍应放在适合该职责的存储中。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go tar.Header.Name包含相对路径时的安全判断方法Go tar.Header.Name包含相对路径时的安全判断方法
上一篇
Go tar.Header.Name包含相对路径时的安全判断方法
Go archive/tar读取归档时限制展开路径的安全方案
下一篇
Go archive/tar读取归档时限制展开路径的安全方案
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    135次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    200次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    146次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    125次使用
  • CMMLU中文大模型评估基准:功能、使用教程与应用场景解析
    CMMLU
    深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
    111次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码