Beego ORM 本身无查询结果缓存能力,需手动将 QueryTable 或 Raw 结果存入 cache 模块(如 Redis),并自行管理缓存生命周期与一致性;RelatedSel 和 LoadRelated 仅为预加载策略,不持久、不跨请求、无 TTL,无法替代缓存。

Beego ORM 本身不带查询结果缓存能力,所谓“ORM 缓存查询”,其实是你手动把 QueryTable 或 Raw 的结果塞进 cache 模块(比如 Redis),再在下次请求时先查缓存、未命中再走 DB。这不是 ORM 自动行为,必须自己控制生命周期和一致性。
为什么不能直接用 ORM 的 RelatedSel 或 LoadRelated 当缓存?
因为 RelatedSel 和 LoadRelated 只是预加载策略,不落盘、不跨请求、不防穿透——它们每次 HTTP 请求都重新查库,和缓存完全无关。常见错误是以为加了 RelatedSel("profile") 就“缓存了关联数据”,其实只是减少了一次 SQL,但没省下任何 DB 连接或网络开销。
- 关联加载仍走完整 ORM 流程:解析结构体、拼 JOIN、执行 Query、映射结果
- 无法设置 TTL,不能主动失效,更新 Profile 后用户列表页依然返回旧头像
- 高并发下多个请求同时触发 LoadRelated,DB 瞬间被打满(典型缓存击穿)
用 Redis 做 ORM 查询结果缓存的实操步骤
核心逻辑:查缓存 → 未命中 → 查 DB → 写缓存(带 TTL)→ 返回。注意 key 设计、结构序列化、空值兜底。
-
key 要带业务语义和参数签名:比如用户列表分页缓存用
"user:list:page=1&size=20&status=1",别用固定字符串如"user_list",否则分页/筛选全串了 -
值必须序列化为字节流:Redis 只存
[]byte,推荐json.Marshal;别直接传 struct 指针,会 panic -
空结果也要缓存(短 TTL):防止缓存穿透,比如查一个根本不存在的
user_id=999999,写入"user:999999"对应空 JSON + 60s 过期 -
更新时同步删缓存:用户改名后,除了
o.Update(),还得bm.Delete("user:" + strconv.Itoa(u.Id))和bm.Delete("user:list:...")
示例片段:
func (c *UserController) Get() {
o := orm.NewOrm()
key := "user:" + c.Ctx.Input.Param(":id")
var user User
<pre class='brush:php;toolbar:false;'>// 1. 先查 Redis 缓存
if err := bm.Get(key, &user); err == nil && user.Id != 0 {
c.Data["json"] = user
c.ServeJSON()
return
}
// 2. 缓存未命中,查 DB
err := o.QueryTable(&User{}).Filter("id", c.Ctx.Input.Param(":id")).One(&user)
if err != nil {
c.CustomAbort(404, "not found")
return
}
// 3. 写回缓存(带 TTL)
data, _ := json.Marshal(user)
bm.Put(key, data, 300*time.Second) // 5 分钟
c.Data["json"] = user
c.ServeJSON()}
Redis 驱动配置不当会导致缓存比 DB 还慢
Beego 的 cache 模块用 Redis 时,默认连接池极小、无超时、无健康检查,线上常出现 read tcp: i/o timeout 或连接堆积。
- 必须显式注册驱动:
cache.Register("redis", &redis.Cache{}),光改配置文件无效 -
AdapterConfig中至少设三项:{"conn_max_lifetime":3600,"pool_size":50,"idle_timeout":180} - 别用
localhost直连 Redis:Docker 或 K8s 环境下 DNS 解析延迟高,改用宿主机 IP 或 Service 名 - 内存缓存(
memory)只适合单机部署且数据量小的场景;多实例时 key 不共享,缓存命中率归零
真正难的不是“怎么塞进 Redis”,而是“什么时候删”和“空值怎么拦”。一次用户资料更新,可能要清掉 5 个相关 key(详情、列表项、统计摘要、权限快照、搜索索引),漏一个就会脏数据。这些逻辑没法靠框架自动推导,得你在业务层写清楚。


















