Beego的Redis缓存必须全局单例初始化,禁止每次请求调用cache.NewCache;需在init()中配置字符串化的conn、dbNum和password,并显式JSON序列化struct,键名须带业务前缀。

Beego 的 cache 模块初始化必须全局单例
每次请求都调用 cache.NewCache("redis", config) 是最常见也最危险的错误。它会反复新建 redigo.Pool,快速耗尽 Redis 连接数,导致 connection refused 或超时。连接池必须只初始化一次,在 init() 函数里完成。
正确做法是:在 models/init.go 或 main.go 中定义全局变量,并在 init() 里初始化:
var RedisCache cache.Cache
func init() {
config := fmt.Sprintf(`{"key":"beego_cache","conn":"127.0.0.1:6379","dbNum":"0","password":""}`)
var err error
RedisCache, err = cache.NewCache("redis", config)
if err != nil {
panic(fmt.Sprintf("failed to init redis cache: %v", err))
}
}
后续所有 controller、service 都直接用这个 RedisCache 变量,别再重复 New。
Put 和 Get 存取 struct 必须手动序列化
cache.Put("user:1001", userStruct, time.Hour) 看似简洁,但底层会调用 fmt.Sprintf("%+v", userStruct),结果不可控:字段顺序不固定、非导出字段丢失、指针值显示地址、JSON tag 完全失效。
真正可靠的做法是显式 JSON 编解码:
- 存之前:
data, _ := json.Marshal(userStruct),再RedisCache.Put(key, data, ttl) - 取之后:
raw := RedisCache.Get(key)→ 得到[]byte,再json.Unmarshal(raw.([]byte), &target) - 别用
GetString()中转 string,多一次内存拷贝且可能因编码问题出错
注意:struct 字段必须首字母大写 + 加 json:"xxx" tag,否则 json.Marshal 会忽略。
配置项里的 conn 和 dbNum 类型要匹配字符串
Beego cache 的 Redis 驱动(基于 redigo)要求配置中的 conn 是完整地址(如 "127.0.0.1:6379"),dbNum 和 password 必须是字符串类型,即使值是数字或空也要加引号。
错误示例(会导致解析失败或连错 DB):
{"conn": "localhost:6379", "dbNum": 0, "password": null}
正确写法(全部字符串):
{"conn": "127.0.0.1:6379", "dbNum": "0", "password": ""}
如果从 app.conf 读取,确保用 beego.AppConfig.String("redis::dbNum"),而不是 DefaultInt —— 后者会把字符串 "0" 当成 0 再转回字符串,看似一样,但驱动内部解析逻辑依赖原始字符串格式。
缓存键名建议带业务前缀,避免跨环境冲突
Beego cache 的配置里有个 key 字段(如 "beego_cache"),它只是驱动内部用的 collection 名,**不影响实际 Redis key**。真实 key 就是你传给 Put() 的第一个参数。
所以务必自己管理命名空间:
- 不要直接
Put("1001", ...),容易和其它服务或模块冲突 - 统一加前缀,比如
Put("user:profile:1001", ...)、Put("article:hotlist", ...) - 测试环境可加
test_前缀,上线前批量替换或通过配置注入
这点容易被忽略,等线上多个服务共用一个 Redis 实例时,key 冲突会导致数据覆盖或误删,排查成本极高。


















