在系统的学习 redis 前的疑惑

序言


🐒:

   有 MySQL 相关的知识,最近要用到 redis ,想要系统的学一下,但需要时间,疑惑需要里面解决,然后去问了 deepseek


一、命令行 vs 可视化 vs Go 代码(怎么分工?)


这三个工具不是 "三选一" ,而是 "三种不同场景" 的利器:

  • 命令行 redis-cli(手术刀)
    • 这是最直接、最专业的调试工具。
    • 当你线上出 Bug(比如怀疑缓存没删掉),直接 SSH 上服务器敲命令查,速度最快,不依赖图形界 面。
    • 建议你必须熟练
  • 可视化界面(显微镜)
    • 主要用于 "个人项目" 和 "开发阶段"
    • 比如你刚写完一段 Go 代码 SET 了一个复杂的 JSON 结构,立刻切到界面刷新一下,直观地 看到数据长什么样,方便你校验逻辑。
    • 但在严肃的生产环境,出于安全考虑,往往不允许随意用 GUI 连接。
  • Go 代码(主力)
    • 这是生产环境业务逻辑的唯一操作方式。
    • 你的增删改查必须写在 Go 里,由用户请求触发。

给你的建议 :平时写 Go 代码逻辑,写完后用可视化界面看一眼数据对不对;如果数据不对,打开命令行用 GET keyTTL key 精细排查。


二、Go 里有类似 GORM 的 Redis "ORM" 吗?


直接回答:没有,也不需要。

原因很简单

  • GORM 解决的是 "表结构 -> 对象" 的映射(SQL 关系型)。

  • Redis"键值对" + 数据结构String/List/Hash/Zset/Stream)。

Go 世界里,操作 Redis 的标准姿势是 "命令执行器" (即你刚装的 go-redis),它就像 Go 标准库里的 database/sql,负责把 Redis 命令(如 SETHGETZADD)发给服务器。

虽然也有一个叫 redis-om-goRedis 官方出的对象映射库)的东西,试图把结构体自动映射到 Redis Hash ,但在实际生产项目中,90% 以上的开发者依然选择 go-redis + 手动序列> (json.Marshal

因为 Redis 的缓存场景通常只需要存取 JSON 字符串,用 ORM 反而显 得笨重且难以控制过期时间。


三、MySQL vs Redis(核心区别)


概念层次 MySQL(关系型) Redis(键值型) 说明
顶层隔离 数据库(Database) 逻辑索引(DB Index) Redis 默认有 16 个 (编号 0 ~ 15),类似于 16 个独立的 MySQL 数据库。
中间分组 表(Table) ❌ 不存在 Redis 没有表的概念! 所有 Key 都是平铺在同一个 DB 里的。
具体数据 行(Row) + 列(Column) 键(Key) + 值(Value) RedisKey 是唯一的字符串,Value 才是具体数据。

四、为什么数据多起来会 "看起来乱" 甚至 "覆盖" ?


因为 Redis 的 Key 是全局唯一的

  • 你在 DB 0 里创建了一个 Keyuser:1

  • 如果你在同一个 DB 0 里,再创建一个 Key 也叫 user:1新的会把旧的覆盖掉 (和 MySQL 主键冲突报错不同,Redis 直接覆盖)。

那怎么解决呢?

  • 全靠 "规范命名" + "切换 DB"

五、隔离数据的两种实战策略


策略一:用 DB 编号隔离(简单粗暴,适合不同项目)

  • 就像你在 MySQL 里创建 db_projectAdb_projectB 一样。

  • 如何操作

    • Redis16 个库(0-15)就是干这个的。

    • 可视化界面 :在 Another Redis Desktop Manager 左侧,默认显示 DB0,你可以右键点击, 选择 Add Database 或直接切换到 DB1,你会惊讶地发现里面完全是空的(和 DB0 完全隔离)。

    • Go 代码里 :创建客户端时指定 DB: 1,这样你所有代码都只读写 DB1,永远不会碰到 DB0 的 数据。

      go 复制代码
      rdb := redis.NewClient(&redis.Options{
          Addr:     "127.0.0.1:6379",
          Password: "123456",
          DB:       1,  // 就这里,指定用第 2 个库
      })

策略二:用 Key 命名空间隔离(专业规范,推荐!)

  • 因为 Redis 没有 "表" ,业界通用的做法是用 冒号 : 作为分隔符,给 Key 加上 "前缀"

    • 比如做个人博客 :所有缓存 Key 都以 blog:article:1blog:user:2 开头。

    • 比如做电商后台 :所有 Key 都以 order:create:xxx 开头。

  • 在可视化界面里 ,这些 Key 会按字母排序自动归在一起,看起来就像 "表" 一样清晰。这样在 DB0 里混着写,只要 前缀不同(如 projA:projB: ,就绝不会覆盖。

最佳实战建议(别再担心覆盖了)

  • 个人小项目只用 DB0

    • 但强制自己给所有 Key 加上项目前缀,

    • 例如 myblog:user:info

  • 区分开发/测试使用不同的 DB 编号

    • 比如 DB 0 给开发环境,DB 1 给单元测试环境。

    • 这样跑测试时即使删库(FLUSHDB),也只会清掉 DB1,开发环境的数据毫发无损。

总结:

不用担心数据杂乱或覆盖,只要你养成 "项目用固定 DB + Key 加业务前缀" 的习惯,Redis 的数据管理完全可以像 MySQL 一样井井有条。


六、实际业务中(公司项目):只用 DB 0,甚至禁止切换


  • 云厂商限制

    • 阿里云、AWS 等托管的 Redis 默认只允许使用 DB 0

    • 你执行 SELECT 1 会直接报错。

    • 因为云厂商为了高性能和运维简单,关掉了多 DB 功能。

  • Redis Cluster(集群)

    • 只要你用到分布式集群模式只有 DB 0 可用

    • 不支持多 DB

  • 隔离方式

    • 大厂根本不用 DB 编号隔离。

    • 不同业务(订单、用户、商品)直接部署不同的 Redis 实例(不同 IP 或端口) ,物理隔离,互不影 响。

结论 :在公司,领导或架构师会指定 "连接哪个 Redis 地址" ,而不是 "用哪个 DB 编号" 。你在代码里永远写 DB: 0


七、个人项目中(你的练手项目):也建议只用 DB 0


  • 原因

    • 为了和 "云上生产环境" 保持一致,提前养成好习惯

    • 如果个人项目用了 DB 1,将来上线到阿里云发现不支持,代码还得改,麻烦。

  • 那怎么隔离不同模块(比如用户模块和订单模块)?

    • 用 Key 前缀!比如:

      • 用户数据:user:profile:1001

      • 订单数据:order:detail:20240719001

      • 在可视化界面(Another Redis Desktop Manager )里,这些 Key 会按字母顺序自动排在一 起,看起来就像分好组了,完全不乱。


八、那什么时候才会用到 DB 1、DB 2...?


仅限于本地开发测试的 "特殊场景"

  • 跑单元测试 :代码里写 DB: 1,测试前执行 FLUSHDB 清空,完全不影响你 DB 0 里的开发数据。

  • 临时做实验 :想试试某个命令会不会搞乱数据,切到 DB 5 随便玩,玩坏了直接删库(删 DB 5), 不影响主库。


九、这是一份 "生产级习惯" 的 Go 代码示范


下面这份代码展示了正确的做法 :永远只用 DB: 0,但通过配置常量Key 前缀来区分业务。

go 复制代码
package main

import (
	"context"
	"fmt"
	"log"
	"time"

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

// 1. 定义业务前缀常量(就像 MySQL 里的表名)
const (
	KeyPrefixUser  = "user:"
	KeyPrefixOrder = "order:"
)

func main() {
	// 2. 永远连接 DB 0(和生产环境保持一致)
	rdb := redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379",
		Password: "123456",
		DB:       0, // 固定写 0,不要改!
	})
	ctx := context.Background()

	// 3. 写入数据时,拼接前缀
	userKey := KeyPrefixUser + "profile_1001"
	orderKey := KeyPrefixOrder + "detail_001"

	err := rdb.Set(ctx, userKey, "{name: '张三'}", 10*time.Minute).Err()
	if err != nil {
		log.Fatal(err)
	}
	err = rdb.Set(ctx, orderKey, "{total: 99.9}", 10*time.Minute).Err()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("✅ 写入成功: %s 和 %s\n", userKey, orderKey)

	// 4. 读取时也带前缀
	val, _ := rdb.Get(ctx, userKey).Result()
	fmt.Printf("🔍 读取 user 数据: %s\n", val)

	// 5. 查看所有 Key(你会发现它们排列得很整齐)
	keys, _ := rdb.Keys(ctx, "*").Result()
	fmt.Printf("📋 当前所有 Key: %v\n", keys)
}

相关推荐
吴声子夜歌8 小时前
Redis 3.x——集群故障转移
java·数据库·redis·集群
名字还没想好☜9 小时前
Go 用 errgroup 管理并发子任务:错误收敛、取消传播与限流
开发语言·后端·golang·go·并发
海兰10 小时前
【高速缓存】RedisVL 指南:从向量搜索到 AI 应用落地
人工智能·redis
weixin_7275356210 小时前
双Token认证体系深度拆解:Spring Security + JWT + Redis
redis·spring·wpf
William Dawson11 小时前
【华为云 MRS Redis 安全集群 Kerberos 认证接入实战(Spring Boot \+ Jedis)】
redis·安全·华为云
zhouhui00112 小时前
AI帮我写了个Spring Boot校验,线上漏掉了这组边界条件
java·spring boot·redis·ai编程
吃饱了得干活12 小时前
扫码登录如何实现?从原理到实战
java·spring boot·redis
labixiong12 小时前
TypeScript 7.0 编译器用 Go 重写,速度暴增10倍——背后到底做了什么?
前端·javascript·go
名字还没想好☜1 天前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器