Beego cache.NewCache("file") 不能创建多个独立实例,因其对每种驱动类型仅维护一个全局单例,多次调用会覆盖配置且返回同一内存地址;多目录隔离需用命名空间或换驱动。

Beego cache.NewCache("file") 为什么不能创建多个独立实例
因为 Beego 的 cache 模块对每个驱动类型(如 "file")只维护一个全局适配器实例,底层通过 adapters["file"] 单例存储。连续调用两次 cache.NewCache("file", config1) 和 cache.NewCache("file", config2),第二次会覆盖第一次的配置和状态,且返回的两个变量实际指向同一内存地址——所有 Put/Get 操作都落在最后初始化的那个目录下。
这不是 bug,是设计如此。你无法靠多次 NewCache 实现「多文件缓存目录隔离」。
- 想用多个缓存目录?必须改用命名空间前缀 + 单实例方案
- 想彻底物理隔离?只能换驱动,比如一个用
"file",另一个用"memory"或"redis" - 检查是否复用:打印
fmt.Printf("%p", bm),两个"file"实例地址必然相同
Redis 驱动配置中 conn 字段格式容易写错
conn 不是 URL,而是纯地址+端口字符串,不支持 redis:// 前缀或查询参数。常见错误是写成 "redis://127.0.0.1:6379" 或 "127.0.0.1:6379?db=0",这会导致连接失败并静默返回 nil,Get 永远返回 nil。
- 正确写法:
{"conn":"127.0.0.1:6379"}或{"conn":":6379"}(本地 Unix 域 socket 可省略 host) - 密码非空时必须显式传
password字段,空字符串""会被 redigo 当作无密码处理 -
dbNum是字符串类型,不是整数,写"1"合法,写1会解析失败
Memory 驱动的 interval 参数影响 GC 频率但不控制单 key 过期
memory 驱动的配置 {"interval":60} 表示每 60 秒触发一次全局过期扫描,但它不会实时清理已过期的 key。这意味着:
- 一个 key 设置了 10 秒过期,第 11 秒调用
Get仍可能返回旧值,直到下次 GC 扫描执行 - 高并发场景下,大量短 TTL key 可能堆积,GC 延迟导致内存占用虚高
- 若业务要求严格准时过期(如 token 校验),memory 驱动不适合,应换 redis
别指望 interval 越小越好——设成 5 会频繁锁住整个缓存 map,反而降低吞吐。
自定义驱动注册后 init 函数必须在 main 包或被 main 导入
Beego cache 的驱动注册依赖 init() 函数自动执行,而 Go 的 init 只在包被直接或间接导入到 main 包时才触发。如果你把自定义驱动放在一个未被 main.go 引用的子包里,Register("mycache", NewMyCache()) 根本不会运行,后续 NewCache("mycache", ...) 会 panic:unknown adapter。
- 验证方式:在自定义驱动的
init里加log.Println("mycache registered"),启动时没输出就说明没加载 - 确保该包路径出现在
main.go的 import 列表中,哪怕只是空白导入:_ "your/project/cache/mydriver" - 不要试图在运行时动态注册——
Register只能在 init 阶段调用,否则 panic
多驱动混用本身不难,真正容易卡住的是驱动间的行为差异:file 的单例限制、memory 的 GC 延迟、redis 的连接池复用策略、以及所有驱动对空值/序列化错误的静默处理习惯。上线前务必用真实流量压测缓存失效路径。



















