在系统的学习 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)
}

相关推荐
小满zs6 小时前
Go语言第八章(函数)
后端·go
stark张宇8 小时前
实战Go高级特性:Context超时控制、defer资源回收与Channel通信的关键避坑点
后端·go
海上小飞龙11 小时前
Redis 分布式锁原理:从 SET NX EX 到 Redisson 看门狗
数据库·redis·分布式
万物皆字节14 小时前
【避坑】使用CacheEvict需要注意的坑
redis
程序员爱钓鱼21 小时前
Go 类型转换详解
后端·面试·go
范什么特西1 天前
回答知识总结04(redis)
数据库·redis·缓存
朦胧之1 天前
Go 基础
后端·go
higherzjm2 天前
如何通过Linux命令自动切割nginx和redis日志
linux·redis·nginx
似璟如你2 天前
Java 开发者的 Go 语法基础:从 0 开始快速上手 Go
java·开发语言·后端·golang·go·编程语言
PC2005-cloud2 天前
Redis学习笔记:Cluster 集群读写分离实战,Lettuce + Spring Boot 从配置到验证
redis·笔记·学习