缓存系统
最后更新: 2026-01-27 11:02:47缓存系统
Unicode Framework 提供了灵活的缓存系统,支持文件缓存、Redis 缓存和标签缓存。
缓存基础
缓存接口
所有缓存实现都遵循 CacheInterface 接口:
use Unicode\Framework\Interfaces\CacheInterface;
interface CacheInterface
{
public function get(string $key, mixed $default = null): mixed;
public function set(string $key, mixed $value, ?int $ttl = null): bool;
public function delete(string $key): bool;
public function clear(): bool;
public function has(string $key): bool;
}
文件缓存
基本使用
use Unicode\Framework\Cache\FileCache;
$cache = new FileCache(
directory: 'runtime/cache',
defaultTtl: 3600
);
// 设置缓存
$cache->set('user:1', $userData, 3600);
// 获取缓存
$userData = $cache->get('user:1');
// 删除缓存
$cache->delete('user:1');
// 检查缓存是否存在
if ($cache->has('user:1')) {
$userData = $cache->get('user:1');
}
配置
$cache = new FileCache(
directory: 'runtime/cache', // 缓存目录
defaultTtl: 3600, // 默认过期时间(秒)
prefix: 'app:', // 键前缀
);
Redis 缓存
基本使用
use Unicode\Framework\Cache\RedisCache;
$cache = new RedisCache(
dsn: 'redis://127.0.0.1:6379',
password: null,
database: 1,
prefix: 'cache:',
defaultTtl: 3600
);
// 设置缓存
$cache->set('user:1', $userData, 3600);
// 获取缓存
$userData = $cache->get('user:1');
// 删除缓存
$cache->delete('user:1');
配置
$cache = new RedisCache(
dsn: 'redis://127.0.0.1:6379', // Redis DSN
password: 'your-password', // Redis 密码(可选)
database: 1, // 数据库编号
prefix: 'cache:', // 键前缀
defaultTtl: 3600, // 默认过期时间(秒)
);
DSN 格式
redis://[password@]host[:port][/database]
redis://127.0.0.1:6379
redis://password@127.0.0.1:6379/1
标签缓存
标签缓存允许您为一组相关的缓存项添加标签,然后批量清除。
基本使用
use Unicode\Framework\Cache\TaggedCache;
// 创建标签缓存(需要底层缓存支持)
$taggedCache = new TaggedCache($cache, ['users']);
// 设置带标签的缓存
$taggedCache->set('user:1', $userData, 3600);
$taggedCache->set('user:2', $userData2, 3600);
// 清除该标签的所有缓存
$taggedCache->flush(); // 清除所有 'users' 标签的缓存
多标签
$taggedCache = new TaggedCache($cache, ['users', 'active']);
// 设置缓存(带有 users 和 active 两个标签)
$taggedCache->set('user:1', $userData, 3600);
// 清除任一标签的所有缓存
$taggedCache->flush(); // 清除所有 users 或 active 标签的缓存
缓存操作
设置缓存
// 使用默认 TTL
$cache->set('key', 'value');
// 指定 TTL(秒)
$cache->set('key', 'value', 3600);
// 永久缓存(不设置 TTL)
$cache->set('key', 'value', null);
获取缓存
// 获取缓存
$value = $cache->get('key');
// 获取缓存,如果不存在返回默认值
$value = $cache->get('key', 'default');
// 获取缓存,如果不存在执行回调
$value = $cache->get('key', function() {
return expensiveOperation();
});
删除缓存
// 删除单个缓存
$cache->delete('key');
// 删除多个缓存
$cache->delete('key1');
$cache->delete('key2');
// 清空所有缓存
$cache->clear();
检查缓存
// 检查缓存是否存在
if ($cache->has('key')) {
$value = $cache->get('key');
}
获取或设置
// 如果缓存不存在,执行回调并缓存结果
$value = $cache->get('key', function() {
$data = expensiveOperation();
$cache->set('key', $data, 3600);
return $data;
});
缓存模式
缓存穿透
缓存穿透是指查询一个不存在的数据,导致每次查询都访问数据库。
解决方案:// 缓存空值
$user = $cache->get('user:999', function() {
$user = db('users')->where('id', 999)->first();
if ($user === null) {
// 缓存空值,设置较短的过期时间
$cache->set('user:999', null, 60);
return null;
}
$cache->set('user:999', $user, 3600);
return $user;
});
缓存击穿
缓存击穿是指热点数据过期,大量请求同时访问数据库。
解决方案:// 使用锁机制
$lockKey = 'lock:user:1';
if ($cache->has($lockKey)) {
// 等待其他请求完成
sleep(0.1);
return $cache->get('user:1');
}
// 设置锁
$cache->set($lockKey, true, 10);
try {
$user = db('users')->where('id', 1)->first();
$cache->set('user:1', $user, 3600);
} finally {
$cache->delete($lockKey);
}
缓存雪崩
缓存雪崩是指大量缓存同时过期,导致大量请求访问数据库。
解决方案:// 为缓存过期时间添加随机值
$ttl = 3600 + rand(0, 600); // 3600-4200 秒
$cache->set('key', $value, $ttl);
最佳实践
1. 缓存键命名
// ✅ 推荐:使用有意义的键名
$cache->set('user:1', $user);
$cache->set('user:1:profile', $profile);
$cache->set('post:123:comments', $comments);
// ❌ 错误:使用无意义的键名
$cache->set('a1', $user);
$cache->set('b2', $profile);
2. 缓存过期时间
// ✅ 推荐:根据数据更新频率设置过期时间
$cache->set('user:1', $user, 3600); // 用户数据:1小时
$cache->set('config:app', $config, 86400); // 配置数据:24小时
$cache->set('stats:daily', $stats, 3600); // 统计数据:1小时
// ❌ 错误:所有数据使用相同的过期时间
$cache->set('user:1', $user, 3600);
$cache->set('config:app', $config, 3600); // 配置数据不应该频繁过期
3. 缓存更新策略
// ✅ 推荐:更新数据时同时更新缓存
public function updateUser(int $id, array $data): void
{
db('users')->where('id', $id)->update($data);
// 更新缓存
$user = db('users')->where('id', $id)->first();
$cache->set("user:{$id}", $user, 3600);
// 清除相关缓存
$taggedCache = new TaggedCache($cache, ['users']);
$taggedCache->flush();
}
// ❌ 错误:只更新数据库,不更新缓存
public function updateUser(int $id, array $data): void
{
db('users')->where('id', $id)->update($data);
// 缓存仍然是旧数据
}
4. 使用标签缓存
// ✅ 推荐:使用标签缓存管理相关数据
$taggedCache = new TaggedCache($cache, ['users']);
// 设置用户相关缓存
$taggedCache->set('user:1', $user1, 3600);
$taggedCache->set('user:2', $user2, 3600);
$taggedCache->set('user:list', $userList, 3600);
// 用户数据更新时,清除所有用户相关缓存
$taggedCache->flush();
5. 缓存预热
// ✅ 推荐:应用启动时预热常用数据
public function warmUpCache(): void
{
// 预热配置缓存
$config = db('config')->get();
$cache->set('config:all', $config, 86400);
// 预热热门数据
$hotUsers = db('users')
->where('status', 'active')
->orderBy('views', 'desc')
->limit(100)
->get();
foreach ($hotUsers as $user) {
$cache->set("user:{$user['id']}", $user, 3600);
}
}
6. 缓存监控
// ✅ 推荐:监控缓存命中率
class CacheMonitor
{
private int $hits = 0;
private int $misses = 0;
public function get(string $key, callable $callback): mixed
{
if ($cache->has($key)) {
$this->hits++;
return $cache->get($key);
}
$this->misses++;
$value = $callback();
$cache->set($key, $value, 3600);
return $value;
}
public function getHitRate(): float
{
$total = $this->hits + $this->misses;
return $total > 0 ? ($this->hits / $total) * 100 : 0;
}
}
常见问题
Q: 如何选择缓存驱动?
A:
- 文件缓存:适合小型应用,不需要额外服务
- Redis 缓存:适合中大型应用,需要高性能和分布式支持
Q: 缓存键冲突怎么办?
A: 使用前缀区分不同模块的缓存:
$userCache = new FileCache('runtime/cache', 3600, 'user:');
$configCache = new FileCache('runtime/cache', 86400, 'config:');
Q: 如何清除所有缓存?
A: 使用 clear() 方法:
$cache->clear();
Q: 缓存数据如何序列化?
A: 框架自动处理序列化,支持字符串、数组、对象等数据类型。
Q: 如何实现缓存分布式?
A: 使用 Redis 缓存,Redis 天然支持分布式。