序言
🐒:
有 MySQL 相关的知识,最近要用到 redis ,想要系统的学一下,但需要时间,疑惑需要里面解决,然后去问了 deepseek 。
一、命令行 vs 可视化 vs Go 代码(怎么分工?)
这三个工具不是 "三选一" ,而是 "三种不同场景" 的利器:
- 命令行
redis-cli(手术刀)
- 这是最直接、最专业的调试工具。
- 当你线上出 Bug(比如怀疑缓存没删掉),直接 SSH 上服务器敲命令查,速度最快,不依赖图形界 面。
- 建议你必须熟练。
- 可视化界面(显微镜) :
- 主要用于 "个人项目" 和 "开发阶段" 。
- 比如你刚写完一段 Go 代码
SET了一个复杂的JSON结构,立刻切到界面刷新一下,直观地 看到数据长什么样,方便你校验逻辑。- 但在严肃的生产环境,出于安全考虑,往往不允许随意用 GUI 连接。
- Go 代码(主力) :
- 这是生产环境 和业务逻辑的唯一操作方式。
- 你的增删改查必须写在 Go 里,由用户请求触发。
给你的建议 :平时写 Go 代码逻辑,写完后用可视化界面看一眼数据对不对;如果数据不对,打开命令行用
GET key或TTL key精细排查。
二、Go 里有类似 GORM 的 Redis "ORM" 吗?
直接回答:没有,也不需要。
原因很简单:
GORM 解决的是 "表结构 -> 对象" 的映射(SQL 关系型)。
Redis 是 "键值对" + 数据结构 (
String/List/Hash/Zset/Stream)。在 Go 世界里,操作 Redis 的标准姿势是 "命令执行器" (即你刚装的
go-redis),它就像 Go 标准库里的database/sql,负责把 Redis 命令(如SET、HGET、ZADD)发给服务器。虽然也有一个叫
redis-om-go(Redis 官方出的对象映射库)的东西,试图把结构体自动映射到 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) | Redis 的 Key 是唯一的字符串,Value 才是具体数据。 |
四、为什么数据多起来会 "看起来乱" 甚至 "覆盖" ?
因为 Redis 的 Key 是全局唯一的。
你在 DB
0里创建了一个 Key 叫user:1。如果你在同一个 DB
0里,再创建一个 Key 也叫user:1,新的会把旧的覆盖掉 (和 MySQL 主键冲突报错不同,Redis 直接覆盖)。那怎么解决呢?
- 全靠 "规范命名" + "切换 DB" 。
五、隔离数据的两种实战策略
策略一:用 DB 编号隔离(简单粗暴,适合不同项目)
就像你在 MySQL 里创建
db_projectA和db_projectB一样。如何操作:
Redis 的 16 个库(
0-15)就是干这个的。可视化界面 :在 Another Redis Desktop Manager 左侧,默认显示
DB0,你可以右键点击, 选择Add Database或直接切换到DB1,你会惊讶地发现里面完全是空的(和DB0完全隔离)。Go 代码里 :创建客户端时指定
DB: 1,这样你所有代码都只读写DB1,永远不会碰到DB0的 数据。
gordb := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "123456", DB: 1, // 就这里,指定用第 2 个库 })策略二:用 Key 命名空间隔离(专业规范,推荐!)
因为 Redis 没有 "表" ,业界通用的做法是用
冒号 :作为分隔符,给 Key 加上 "前缀"。
比如做个人博客 :所有缓存 Key 都以
blog:article:1、blog: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)
}