缓存与性能规范
Redis 使用规范、缓存键设计、N+1 优化、列表/详情缓存策略。
1. 缓存键命名
统一前缀 + 业务 + 维度,dataprefix 由 web.prefix 注入:
<dataprefix>_<业务>_<主键> 如 typecho_soft_info_12
<dataprefix>_<业务>_<主键>_<维度> 如 typecho_soft_info_12_3(uid 维度)
<dataprefix>_<业务>_<page>_<limit> 列表缓存
用户态相关缓存必须带 uid:付费状态、已购状态、浏览偏好等。不带 uid 会导致 A 用户状态暴露给 B 用户。
2. 读写规范
// 写(TTL 秒)
redisHelp.setRedis(key, jsonString, 30, redisTemplate);
// 读
String v = redisHelp.getRedis(key, redisTemplate);
// 列表
redisHelp.setList(key, jsonList, 30, redisTemplate);
List l = redisHelp.getList(key, redisTemplate);
// 删单条 / 按模式删
redisHelp.delete(key, redisTemplate);
redisHelp.deleteKeysWithPattern("*" + dataprefix + "_xxx_*" + uid, redisTemplate, dataprefix);
- TTL:详情类 30~60s、配置类更长、用户态不宜太长(余额/状态)。
- 写后删(cache-aside):变更数据后删除对应缓存,让下次请求重建。
- 更新表结构/数据修复后必须清相关缓存(配合管理端"清除缓存")。
3. 列表缓存与登录用户
软库/商城列表对未登录用户走共享短缓存(30s),登录用户直查库以返回个性化 isPaid 等:
if (!isAdmin && loginUid == 0) {
// 命中缓存直接返回
}
// 否则查库 + 附加登录态字段
好处:命中率高 + 状态准确。代价:登录用户列表稍慢(可控)。
4. N+1 优化
在列表循环中批量查询关联数据,禁止逐条 selectByKey:
// 收集所有 id
List<Integer> ids = ...;
// 批量查(in 查询或缓存 Map)
Map<Integer, UserInfo> map = ...;
for (item : list) { json.put("userJson", map.get(item.getUid())); }
参考:SoftController.list 的批查 userJson/honor/已购、SpaceController.spaceList 的批量关联。
5. 性能底线
- 列表接口必须分页(
limit上限 50)。 - 高频只读接口配短缓存;写接口防刷限频。
- 避免大字段(正文、截图列表)在列表里全量返回——列表转发用摘要字段。
- 服务端渲染站点(Sulo)注意 SSR 首屏数据接口的缓存友好(
useAsyncData复用)。
6. 常见坑
- 缓存键忘加业务名 → 跨模块冲突。
- 更新数据库后忘删缓存 → 数据回退展示。
- 列表缓存 key 未含筛选参数 → 不同筛选串数据。
- N+1 未优化 → 列表 N 次查询(20 条 20 次 SQL)拖垮接口。