RedisJSON中JSON.SET的用法小结

 更新时间:2025年11月12日 11:26:00   作者:Hello.Reader  
本文全面解析 RedisJSON 插件的核心指令JSON.SET,涵盖语法规则、典型用法、易错点和性能优化建议,感兴趣的可以了解一下

1 · 为什么要写这篇文章?

在结构化数据存储场景里,传统的字符串键值对已难以满足灵活查询与字段级更新的需求。RedisJSON 插件为 Redis 带来了对原生 JSON 文档的读写支持,其中最核心也最常用的指令就是 JSON.SET。本文将带你彻底吃透 JSON.SET 的各个细节——从语法、时间复杂度到多路径批量更新,再到在生产环境中容易踩到的坑和性能调优方法,并提供一套 Go-Redis 的完整示例代码,帮助你快速落地。

2 · RedisJSON 与 JSON.SET 概览

特性说明
插件版本RedisJSON ≥ 1.0 (推荐 2.x 与 Redis 7.x+ 搭配使用)
指令`JSON.SET key path value [NXXX]`
功能按 JSONPath 将 value 写入 key 对应的 JSON 文档
ACL 标记@json @write @slow
时间复杂度O(M + N) —— M 为原值大小,N 为新值大小 × 匹配路径数

3 · 语法详解

JSON.SET <key> <path> <value> [NX | XX]
参数必填说明
keyRedis 中的键;不存在时必须从根路径写入
pathJSONPath 表达式;$ 或 . 代表根
value合法 JSON 字符串,或原样字符串(无需额外引号)
NX仅当目标不存在时写入
XX仅当目标已存在时覆盖

小贴士:NX 与 XX 不仅作用于 Redis 键,也作用于 JSON 文档内部键。这点经常被忽略!

4 · JSONPath 规则速查

  • 根路径:$ 或 .
  • 点式:$.address.city
  • 数组下标:$.items[0]
  • 切片:$.items[1:3](RedisJSON 2.x 支持)
  • 通配:$..price 匹配所有层级的 price 字段
  • 多路径:$..a 与 $..b 可一次性传入多条

注意:JSON.SET 不支持在一次调用中写入 不同 的值到多条路径;如果传入多路径,所有匹配点都会被同一个 value 覆盖。

5 · 返回值与错误处理

情况返回
写入成功OK
路径不存在且无法创建(nil)
NX/XX 条件不满足(nil)
根键不存在但路径不是 $(error) ERR new objects must be created at the root

生产环境中推荐显式检查返回值,而不要只依赖 err == nil。示例见 § 9。

6 · 典型用法示例

6.1 替换已有字段

redis> JSON.SET doc $ '{"a":2}'
OK
redis> JSON.SET doc $.a 3
OK
redis> JSON.GET doc $
"[{\"a\":3}]"

6.2 追加新字段

redis> JSON.SET doc $ '{"a":2}'
OK
redis> JSON.SET doc $.b 8
OK
redis> JSON.GET doc $
"[{\"a\":2,\"b\":8}]"

6.3 一次性批量更新多路径

redis> JSON.SET doc $ '{"f1":{"a":1},"f2":{"a":2}}'
OK
redis> JSON.SET doc $..a 3
OK
redis> JSON.GET doc
"{\"f1\":{\"a\":3},\"f2\":{\"a\":3}}"

6.4 结合 NX / XX 条件

# 仅当字段不存在时写入
redis> JSON.SET user:1 $.nickname '"neo"' NX
OK          # 第一次成功
redis> JSON.SET user:1 $.nickname '"smith"' NX
(nil)       # 条件未满足

7 · 易踩坑汇总

现象解决方案
键不存在却写子路径抛错 ERR new objects must be created at the root第一次写必须用根路径 $
值未用 JSON 字符串包裹若忘记加引号:JSON.SET $.name neo ⇒ 解析失败非数值 / 布尔需双引号或 'neo'
NX/XX 作用域误解误以为只检查 Redis 键其实同时检查 JSON 内目标字段
字符串过长超出 512 MB 限制拆分存储或压缩再存

8 · 性能调优与并发安全

  1. Pipeline / MULTI
    连续多次 JSON.SET 可使用 Pipelining 或事务批量发送,减少 RTT。
  2. 避免大文档频繁写
    时间复杂度包含原值大小 M:越大的 JSON,写一次越慢。可将热点字段拆分为独立键或使用 JSON.NUMINCRBY 等增量指令。
  3. 合理选择 NX/XX
    在幂等场景下使用 NX 或 XX 可避免无谓的重写,降低写放大。
  4. 监控慢日志
    Redis 会将执行时间 > slowlog-log-slower-than 的指令记录;JSON 操作本质属 @slow 类别,应重点关注。
  5. Lua/RedisGears 乐观锁
    高并发写同一字段,可结合 WATCH/MULTI 或 Lua 脚本实现 CAS。

9 · Go-Redis 完整示例(可直接运行)

依赖:Go ≥ 1.22、github.com/redis/go-redis/v9

// 文件 main.go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

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

var ctx = context.Background()

type Profile struct {
	Name  string `json:"name"`
	Age   int    `json:"age"`
	Tags  []string `json:"tags"`
}

func must(err error) {
	if err != nil {
		log.Fatalf("fatal: %v", err)
	}
}

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})
	defer rdb.Close()

	// ---------- 1. 写入根文档 ----------
	profile := Profile{Name: "Alice", Age: 27, Tags: []string{"gopher", "redis"}}
	raw, _ := json.Marshal(profile)

	if res, err := rdb.Do(ctx, "JSON.SET", "user:1001", "$", raw).Text(); err != nil {
		must(err)
	} else {
		fmt.Println("set root:", res) // OK
	}

	// ---------- 2. 更新子字段 ----------
	if res, err := rdb.Do(ctx, "JSON.SET", "user:1001", "$.age", 28, "XX").Text(); err != nil {
		must(err)
	} else if res == "" {
		fmt.Println("XX unmet, age not updated")
	} else {
		fmt.Println("update age:", res) // OK
	}

	// ---------- 3. 读取文档 ----------
	data, err := rdb.Do(ctx, "JSON.GET", "user:1001", "$").Result()
	must(err)
	fmt.Println("profile =", data.(string))

	// ---------- 4. 错误示例 ----------
	if _, err := rdb.Do(ctx, "JSON.SET", "user:1002", "$.name", "\"Bob\"").Result(); err != nil {
		fmt.Println("expected error:", err)
	}

	// Output:
	// set root: OK
	// update age: OK
	// profile = [{"name":"Alice","age":28,"tags":["gopher","redis"]}]
	// expected error: ERR new objects must be created at the root
}

运行后,你将看到成功写入、条件更新、读回以及错误处理的完整流程。

10 · 进阶话题

方向价值
与 RediSearch 集成对 JSON 字段建立二级索引,支持全文检索与聚合分析
存储版本化配置使用 NX 写入新版本,配合 JSON.NUMINCRBY 维护版本号
灰度发布通过数组/对象结构保存多线路配置信息,再用 JSON.DEL 快速回滚
Streaming JSON将大文档拆分到 Stream 或 List,再按需合并到 RedisJSON

11 · 总结

  • JSON.SET 是 RedisJSON 最核心的写入指令,先掌握根写入,再逐步学习多路径与条件写。
  • 时间复杂度与文档大小 线性相关,因此避免频繁重写大 JSON。
  • 正确使用 NX/XX 可实现幂等更新、乐观锁等高级场景。
  • 在 Go-Redis 中通过 Do(ctx, "JSON.SET", …) 可无缝调用,务必检查返回值而非只关注 err。
  • 生产环境要结合 慢日志、Pipeline、事务 等手段进行性能与可靠性保障。

到此这篇关于RedisJSON中JSON.SET的用法小结的文章就介绍到这了,更多相关RedisJSON JSON.SET内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redis 脚本和连接命令示例详解

    Redis 脚本和连接命令示例详解

    Redis脚本是一种可以实现复杂任务的脚本语言,可以用来快速履行复杂任务,灵活处理数据管理和管理复杂的利用场景,这篇文章主要介绍了Redis 脚本和连接命令,需要的朋友可以参考下
    2023-09-09
  • 分布式使用Redis实现数据库对象自增主键ID

    分布式使用Redis实现数据库对象自增主键ID

    本文介绍在分布式项目中使用Redis生成对象的自增主键ID,通过Redis的INCR等命令实现计数器功能,具有一定的参考价值,感兴趣的可以了解一下
    2024-12-12
  • 详解Redis BoundValueOperations使用及实现

    详解Redis BoundValueOperations使用及实现

    BoundValueOperations是Spring Data Redis中一个非常实用的工具,本文主要介绍了Redis BoundValueOperations使用,具有一定的参考价值,感兴趣的可以了解一下
    2025-09-09
  • windows下通过批处理脚本启动redis的操作

    windows下通过批处理脚本启动redis的操作

    本文主要给大家介绍了windows下通过批处理脚本启动redis的操作,windows下redis启动,需要进入redis安装目录,然后shift+右键,选择“在此处打开命令窗口”,然后输入redis-server.exe redis.conf,就可以启动redis了,文中有详细的图文参考,感兴趣的朋友可以参考下
    2023-12-12
  • 通过docker和docker-compose安装redis两种方式详解

    通过docker和docker-compose安装redis两种方式详解

    这篇文章主要介绍了通过docker和docker-compose安装redis的两种方式,Docker安装方式包括拉取镜像、查看本地镜像、运行容器和测试连接,Docker Compose安装方式包括目录结构、配置文件、启动和关闭容器、检查启动情况以及查看CPU和内存使用状态,需要的朋友可以参考下
    2024-12-12
  • 浅谈Redis Key 命名规范文档

    浅谈Redis Key 命名规范文档

    本文介绍了Redis键名命名规范,包括命名格式、具体规范、数据类型扩展命名、时间敏感型键名、规范总结以及实际应用示例,感兴趣的可以了解一下
    2025-05-05
  • 基于Redis分布式锁的实现代码

    基于Redis分布式锁的实现代码

    这篇文章主要介绍了Redis分布式锁的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • shell脚本批量导出redis key-value方式

    shell脚本批量导出redis key-value方式

    为避免keys全量扫描导致Redis卡顿,可先通过dump.rdb备份文件在本地恢复,再使用scan命令渐进导出key-value,通过CNT和INTERVAL参数控制负载,且scan不指定游标可减少阻塞
    2025-08-08
  • 浅谈一下如何保证Redis缓存与数据库的一致性

    浅谈一下如何保证Redis缓存与数据库的一致性

    这篇文章主要介绍了一下如何保证Redis缓存与数据库的一致性,今天这篇文章就带你详细了解一下四种同步策略,需要的朋友可以参考下
    2023-03-03
  • Web-ssrfme:redis 未授权访问攻击的问题解决

    Web-ssrfme:redis 未授权访问攻击的问题解决

    本文主要介绍了Web-ssrfme:redis 未授权访问攻击的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04

最新评论