缓存标签
缓存标签(Cache Tag)为缓存键提供逻辑分组能力:写入时把键挂到标签集合上,之后可按标签批量清除,是「更新即失效」缓存策略的核心工具。
工作原理
每个标签维护一个集合(Set),成员是归属于该标签的缓存键;另有一个标签仓库(Tag Store,键名默认 TAG_STORE)记录所有已注册标签,供 getTags() 全局查询。
text
TAG_STORE(标签仓库)
├── tag:users → [user:1, user:2, user:3]
├── tag:posts → [post:1, post:2]
└── tag:vip → [user:2]标签键默认加 tag: 前缀以区别于普通缓存键,两者均存储在当前驱动中(可通过驱动的 tag_prefix / tag_store 参数调整,见 缓存驱动)。
基本用法
写入时关联标签
Cache::tag() 接受字符串或字符串数组,返回标签实例;用标签实例的 set() 写入,键会自动追加到所有关联标签的集合中:
php
use Viswoole\Cache\Facade\Cache;
// 单标签
Cache::tag('users')->set('user:1', ['name' => '张三'], 3600);
Cache::tag('users')->set('user:2', ['name' => '李四'], 3600);
// 多标签:该缓存同时归属 posts 与 content 两个分组
Cache::tag(['posts', 'content'])->set('post:1', $article, 3600);标签实例的 set() 签名与驱动一致:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| key | string | 必填 | 缓存键 |
| value | mixed | 必填 | 缓存值 |
| expire | DateTime|int|null | null | 过期秒数,null 使用驱动默认值 |
| NX | bool | false | 仅当键不存在时写入 |
挂载已有缓存
对已通过 Cache::set() 写入的键,可用 push() 补挂到标签上:
php
Cache::set('article:100', $data, 3600);
Cache::tag('articles')->push('article:100');查询标签下的缓存键
php
// 单标签:返回扁平键列表 ['user:1', 'user:2']
$keys = Cache::tag('users')->get();
// 多标签:返回按标签分组的映射 ['posts' => [...], 'content' => [...]]
$grouped = Cache::tag(['posts', 'content'])->get();移除指定缓存
remove() 将缓存键从标签集合中剔除并删除缓存数据;若某标签因此变空,该标签也会从标签仓库中移除:
php
Cache::tag('users')->remove('user:1');
Cache::tag(['users', 'vip'])->remove(['user:2', 'user:3']);清空整组缓存
clear() 删除标签下全部缓存数据、标签集合本身,并从标签仓库中注销该标签:
php
Cache::tag('users')->clear();
// 等价于删除:user:1、user:2、tag:users,并从 TAG_STORE 移除 users多标签时一次清除所有传入标签:
php
Cache::tag(['posts', 'content'])->clear();API 速查
| 方法 | 返回值 | 说明 |
|---|---|---|
Cache::tag(string|array $tags) | CacheTagInterface | 创建标签实例,标签为空抛 InvalidArgumentException |
->set($key, $value, $expire, $NX) | bool | 写入缓存并自动挂到当前标签 |
->push($key) | void | 将已有缓存键挂到当前标签并注册标签 |
->get() | array | 标签下的缓存键列表(多标签返回分组映射) |
->remove(string|array $keys) | void | 从标签剔除并删除缓存数据 |
->clear() | void | 清空标签下全部缓存并注销标签 |
Cache::getTags() | array|false | 标签仓库中的所有标签,不存在返回 false |
Cache::getTagKey(string $tag) | string | 标签的实际存储键(含 tag: 前缀) |
Cache::getTagStoreName() | string | 标签仓库键名 |
典型场景
用户维度缓存失效
php
class UserService
{
public function getProfile(int $userId): array
{
$key = "profile:{$userId}";
$cached = Cache::get($key);
if ($cached !== null) {
return $cached;
}
$profile = $this->loadFromDb($userId);
Cache::tag("user:{$userId}")->set($key, $profile, 3600);
return $profile;
}
public function updateProfile(int $userId, array $data): void
{
$this->saveToDb($userId, $data);
// 用户资料变更后,该用户名下的所有缓存(资料、权限、统计…)一次失效
Cache::tag("user:{$userId}")->clear();
}
}多维度分组
php
// 文章同时挂到 全部文章 / 作者 / 分类 三个维度
Cache::tag(['articles', "author:{$authorId}", "category:{$categoryId}"])
->set("article:{$id}", $article, 3600);
// 按任一维度独立失效
Cache::tag("author:{$authorId}")->clear();
Cache::tag("category:{$categoryId}")->clear();注意事项
- 标签不能为空:
Cache::tag([])抛出InvalidArgumentException,标签名请传入非空字符串或非空数组 - 清除非原子:
clear()按集合逐个删除,并发写入同组缓存的瞬间可能残留少量键;对强一致场景建议配合业务锁使用 - 性能考量:集合成员极多时
clear()的删除耗时会线性增长,单标签建议控制在合理规模(如按用户、按日期分片) - 存储开销:每个标签额外占用一个集合的存储空间
- 过期残留:键到期被驱动惰性删除后,仍会残留在标签集合中,
clear()时会对已不存在的键做空删除,属正常现象
