缓存标签
缓存标签(Cache Tag)提供对缓存数据的逻辑分组能力,允许按标签批量清除关联缓存,是实现缓存分类管理的核心功能。
工作原理
每个标签维护一个 Set 集合,存储属于该标签的所有缓存键。清除标签时,遍历集合并删除所有关联缓存。
text
┌─────────────────────────────────────────────────┐
│ TAG_STORE │
│ ┌─────────────┬─────────────┬──────────────┐ │
│ │ tag:users │ tag:posts │ tag:products│ │
│ └──────┬──────┴──────┬──────┴──────┬───────┘ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌────▼─────┐ ┌────▼──────┐ │
│ │ user:1 │ │ post:1 │ │ product:1 │ │
│ │ user:2 │ │ post:2 │ │ product:2 │ │
│ │ user:3 │ │ post:3 │ │ product:3 │ │
│ └─────────────┘ └──────────┘ └───────────┘ │
└─────────────────────────────────────────────────┘基本用法
创建标签并写入缓存
php
use Viswoole\Cache\Facade\Cache;
// 创建单一标签
$userTag = Cache::tag('users');
// 写入缓存并自动关联到标签
$userTag->set('user:1', ['name' => '张三'], 3600);
$userTag->set('user:2', ['name' => '李四'], 3600);
$userTag->set('user:3', ['name' => '王五'], 3600);多标签关联
php
// 一个缓存可同时关联多个标签
$postTag = Cache::tag(['posts', 'content']);
$postTag->set('post:1', ['title' => '文章标题'], 3600);
// 该缓存同时属于 posts 和 content 标签手动推送已有缓存到标签
php
// 将已有的缓存键推送到标签
$tag = Cache::tag('articles');
Cache::set('article:100', $data, 3600);
$tag->push('article:100');清除标签缓存
php
// 清除 users 标签下所有缓存
Cache::tag('users')->clear();
// 这会删除:
// - user:1, user:2, user:3 (缓存数据)
// - tag:users (标签集合)
// - 从 TAG_STORE 中移除 users 标签查询标签下的缓存键
php
// 获取标签下所有缓存键
$keys = Cache::tag('users')->get();
// 返回: ['user:1', 'user:2', 'user:3']移除特定缓存与标签的关联
php
$tag = Cache::tag(['users', 'vip']);
// 从标签中移除指定缓存键(同时删除缓存数据)
$tag->remove(['user:2']);
// 如果移除后标签集合为空,标签也会从仓库中删除标签相关 API
| 方法 | 说明 |
|---|---|
tag($name) | 创建标签实例,支持字符串或数组 |
set($key, $value, $expire) | 写入缓存并关联到标签 |
push($key) | 将已有缓存键推送到标签 |
clear() | 清除标签下所有缓存及标签本身 |
get() | 获取标签下所有缓存键列表 |
remove($keys) | 从标签移除指定缓存并删除数据 |
getTags() | 获取所有已注册的标签列表 |
getTagKey($tag) | 获取标签的实际存储键名 |
getTagStoreName() | 获取标签仓库名称 |
典型应用场景
1. 用户资料更新时清除缓存
php
class UserService
{
public function updateUserProfile(int $userId, array $data): void
{
// 更新数据库
User::where('id', $userId)->update($data);
// 清除该用户的所有缓存
Cache::tag("user:{$userId}")->clear();
}
public function getUserProfile(int $userId): array
{
$cacheKey = "profile:{$userId}";
$cacheValue = Cache::get($cacheKey);
if ($cacheValue !== null) {
return $cacheValue;
}
$user = User::find($userId)->toArray();
// 关联到用户标签
Cache::tag("user:{$userId}")->set($cacheKey, $user, 3600);
return $user;
}
}2. 分类数据批量刷新
php
class ProductService
{
public function refreshCategory(int $categoryId): void
{
// 更新分类信息后,清除该分类下所有商品缓存
Cache::tag("category:{$categoryId}")->clear();
// 预热缓存
$products = Product::where('category_id', $categoryId)->get();
$tag = Cache::tag("category:{$categoryId}");
foreach ($products as $product) {
$tag->set("product:{$product->id}", $product->toArray(), 7200);
}
}
}3. 多维度标签管理
php
class ArticleService
{
public function cacheArticle(Article $article): void
{
// 文章同时关联多个维度的标签
$tags = [
"articles", // 全部文章
"author:{$article->author_id}", // 按作者
"category:{$article->category_id}", // 按分类
"status:published", // 按状态
];
Cache::tag($tags)->set("article:{$article->id}", $article->toArray(), 3600);
}
// 按作者清除
public function clearByAuthor(int $authorId): void
{
Cache::tag("author:{$authorId}")->clear();
}
// 按分类清除
public function clearByCategory(int $categoryId): void
{
Cache::tag("category:{$categoryId}")->clear();
}
}注意事项
- 标签不能为空:创建标签时传入空数组会抛出
InvalidArgumentException - 标签名称规范:建议使用有语义的前缀(如
user:、category:)避免冲突 - 性能考量:大量缓存关联同一标签时,
clear()操作可能较慢 - 原子性:
clear()操作不是原子的,并发场景下可能出现部分清除 - 存储开销:每个标签需要额外的 Set 存储空间来维护键列表
