cacheable注解的value填缓存命名空间(如"user:profile"),必须是字符串字面量,用于redis键前缀或逻辑分组;key才决定唯一性,需用spel表达式(如"#userid"或"'user:'+ #id")动态生成。

Cacheable注解的value参数到底填什么
value 参数不是缓存值本身,而是缓存的「存储命名空间」,对应 Redis 中的 key 前缀或 Swoole Table 的逻辑分组。它必须是字符串字面量(不能是变量或表达式),且通常建议与业务域强相关,比如 "user:profile" 或 "order:list"。
填错最常见的后果是:多个方法共用同一 value,导致缓存互相覆盖;或者填了空字符串/纯空格,触发框架默认行为(如 fallback 到类名+方法名),造成预期外的 key 冲突。
- ✅ 推荐写法:
@Cacheable(value="article:detail", ttl=3600) - ❌ 错误写法:
@Cacheable(value=$this->cachePrefix, ...)(PHP 不支持注解里用变量) - ⚠️ 注意:
value不参与 key 计算,它只是分类标识;真正决定缓存唯一性的,是下面说的key参数
key参数怎么写才能正确区分不同参数调用
key 是生成最终缓存键的核心,必须是 SpEL(Spring Expression Language)风格的字符串表达式,Hyperf 会用反射提取方法参数并求值。它决定了“同一个方法、不同入参”是否命中不同缓存项。
常见错误是直接写死字符串(如 key="'user'"),结果所有调用都写进同一个 key;或者误以为能用 PHP 数组语法,实际只能用 SpEL 的 #p0、#p1、#userId 等占位符。
- ✅ 按第一个参数生成 key:
@Cacheable(key="#p0", value="user:info") - ✅ 按命名参数生成复合 key:
@Cacheable(key="'user:' + #userId + ':profile'", value="user:profile") - ✅ 多参数拼接(注意单引号包裹整个表达式):
@Cacheable(key="'order:' + #uid + ':' + #status", value="order:list") - ❌ 错误:
key="user:#userId"(缺少引号,SpEL 解析失败,抛ParseErrorException)
缓存失效和手动清除时,value和key怎么配合
用 @CacheEvict 清除缓存时,value 必须和 @Cacheable 完全一致,而 key 表达式也需保持逻辑对称——否则清不掉。
例如,某个方法用 @Cacheable(key="'user:' + #id", value="user:info") 缓存,那么清除时就得写 @CacheEvict(key="'user:' + #id", value="user:info")。如果清除方法的 key 写成 #id,那实际删的是 "123" 而不是 "user:123",缓存就漏了。
- ✅ 清除单个:
@CacheEvict(key="'user:' + #id", value="user:info") - ✅ 清除整个命名空间(慎用):
@CacheEvict(allEntries=true, value="user:info") - ⚠️ 注意:Hyperf 默认不支持通配符清除(如
key="user:*"),Redis 后端需自行扩展或改用allEntries
为什么有时候缓存没生效,但日志也没报错
最常被忽略的是方法可见性 —— @Cacheable 只对 public 方法 生效。如果目标方法是 protected 或 private,AOP 代理无法拦截,注解完全静默失效,也不会报错。
另一个隐蔽点是返回值类型:Hyperf 的缓存序列化依赖 serialize(),如果方法返回对象且该对象含闭包、资源句柄或未实现 __serialize(),缓存写入会静默失败(Redis 存的是空或 false)。
- ✅ 确保方法为 public:
public function getUserInfo(int $id): array { ... } - ✅ 返回简单数组、标量或可序列化对象(避免
StdClass套嵌资源) - ✅ 开启调试:在
config/autoload/cache.php中确认'default' => 'redis'配置正确,且 Redis 连接可达
缓存键生成逻辑藏在代理层,不打日志就看不到真实 key;真要排查,得在 CacheAspect 相关源码里加临时 var_dump,或者用 redis-cli monitor 抓命令流。











