beego memory缓存引擎读取即淘汰,需用getmulti或回填put;interval是gc周期非ttl;多controller须key前缀隔离;共享实例无法多配置,最小启动无需外部依赖。

Beego 的 memory 缓存引擎完全支持无数据库轻量运行,但必须避开默认的全局单例陷阱和 GC 间隔误配——否则缓存会“突然消失”或“读一次就丢”。
为什么 NewCache("memory", ...) 初始化后数据读一次就没了
这是 memory 引擎的默认行为:调用 Get() 时会自动触发 Delete(),即“读取即淘汰”。这不是 bug,而是设计如此(类似某些消息队列的 peek-and-consume 模式)。
- 如果你需要多次读取同一 key,必须改用
GetMulti([]string{"key"}),它不会删除数据 - 或者改用
IsExist("key")+Get("key")组合,但要注意并发下仍可能被其他 goroutine 删除 - 更稳妥的做法是:业务层自己做一次
Put()回填,例如val := bm.Get("x"); if val != nil { bm.Put("x", val, 300) }
memory 引擎的 interval 参数不是 TTL,而是 GC 周期
{"interval":60} 中的 60 单位是秒,但它控制的是后台 goroutine 扫描过期 key 的频率,不是每个 key 的存活时间。TTL 是你在 Put(key, value, ttl) 第三个参数里单独指定的。
- 如果设
interval过大(如 3600),已过期的 key 可能在内存里滞留一小时才被清理 - 如果设太小(如 1),GC goroutine 频繁唤醒,对高并发服务反而增加调度压力
- 生产建议值:30–180 秒之间,视缓存总量和更新频次权衡
多个 controller 共享同一 memory 缓存实例的正确姿势
Beego 的 cache 模块不支持同类型多实例(比如两个独立的 "memory" 实例),所有 NewCache("memory", cfg) 调用都会复用同一个底层对象。所以不能靠“新建不同配置”来隔离缓存域。
- 必须在 key 层面做命名空间隔离,例如用
"user:123:profile"、"config:site:theme" - 避免直接用原始业务 ID 作 key,否则不同模块容易冲突
- 批量清理某类缓存时,用前缀 +
ClearAll()不行,得自己实现遍历过滤(memory引擎不提供 key 列表接口)
不依赖任何外部服务的最小可行缓存启动代码
以下代码可直接扔进 main.go 或初始化函数中,无需安装额外驱动、无需配置文件、无需启动 Redis/Memcached:
import "github.com/astaxie/beego/cache"
var Cache cache.Cache
func init() {
var err error
Cache, err = cache.NewCache("memory", `{"interval":60}`)
if err != nil {
panic(err)
}
}
// 使用示例
func doSomething() {
Cache.Put("startup_time", time.Now().Unix(), 3600)
t := Cache.Get("startup_time") // 注意:这次读完就没了
fmt.Println(t)
}
真正容易被忽略的是:这个缓存对象是进程级共享的,所有 goroutine 并发读写它。如果你没做 key 前缀隔离,又没控制好 TTL 和 GC 间隔,上线后会出现“缓存明明 Put 了却 Get 不到”的静默失败——问题不在代码语法,而在缓存语义的理解偏差。











