本文目录导读:

在PHP项目中解决数据缓存过期问题,通常有以下几种主流方案,按推荐程度排序:
主动过期(TTL) - 最常用
在写入缓存时设置过期时间,到期自动失效。
// Redis 示例
$redis->setex('user:123', 3600, serialize($userData)); // 1小时过期
// Memcached 示例
$memcached->set('user:123', $userData, 3600);
// 文件缓存示例(手动实现)
function setCache($key, $data, $ttl = 3600) {
$cacheFile = '/tmp/cache/' . md5($key);
$content = [
'expire' => time() + $ttl,
'data' => $data
];
file_put_contents($cacheFile, serialize($content));
}
被动过期(懒加载) - 最可靠
读取时检查过期时间,过期则重新生成。
function getCachedData($key, $callback, $ttl = 3600) {
$cached = Cache::get($key);
if ($cached === null) {
// 缓存不存在或已过期,重新生成
$data = $callback();
Cache::set($key, $data, $ttl);
return $data;
}
return $cached;
}
// 使用示例
$users = getCachedData('users:list', function() {
return DB::table('users')->get();
}, 3600);
主动刷新(Write-Through)
更新数据时同时更新缓存。
function updateUser($userId, $data) {
// 1. 先更新数据库
DB::table('users')->where('id', $userId)->update($data);
// 2. 同时更新缓存
$user = DB::table('users')->find($userId);
Cache::set("user:$userId", $user, 3600);
// 3. 可选:清理相关列表缓存
Cache::forget('users:list');
}
缓存预热 + 定时刷新
// 1. 定时任务(Cron)
// */5 * * * * php /path/to/preheat_cache.php
// preheat_cache.php
function preheatPopularCache() {
$popularUsers = DB::table('users')
->where('login_count', '>', 1000)
->get();
foreach ($popularUsers as $user) {
Cache::set("user:{$user->id}", $user, 3600);
}
// 预热首页数据
$hotData = DB::table('articles')
->where('status', 'published')
->orderBy('views', 'desc')
->limit(20)
->get();
Cache::set('home:hot_articles', $hotData, 3600);
}
二级缓存策略
class TwoLevelCache {
private $local = []; // 本地内存缓存(最快)
public function get($key) {
// 一级:本地内存
if (isset($this->local[$key]) && $this->local[$key]['expire'] > time()) {
return $this->local[$key]['data'];
}
// 二级:Redis/共享缓存
$data = Redis::get($key);
if ($data) {
$this->local[$key] = [
'data' => $data,
'expire' => time() + 60 // 本地缓存1分钟
];
return $data;
}
return null;
}
}
锁机制(防止缓存雪崩)
function getExpensiveData($key, $ttl = 3600) {
$data = Cache::get($key);
if ($data === null) {
// 获取锁,防止多个请求同时重建缓存
$lockKey = $key . ':lock';
$lock = Cache::lock($lockKey, 10); // 10秒超时
if ($lock->get()) {
try {
// 双重检查
$data = Cache::get($key);
if ($data === null) {
$data = heavyDatabaseQuery();
Cache::set($key, $data, $ttl);
}
} finally {
$lock->release();
}
} else {
// 等待锁释放后重试
usleep(100000); // 等100ms
return $this->getExpensiveData($key, $ttl);
}
}
return $data;
}
缓存版本控制
class VersionedCache {
private $versionKey = 'cache:version';
public function get($key) {
$version = Cache::get($this->versionKey) ?? 1;
return Cache::get("{$key}:v{$version}");
}
public function set($key, $data, $ttl = 3600) {
$version = Cache::get($this->versionKey) ?? 1;
Cache::set("{$key}:v{$version}", $data, $ttl);
}
public function invalidateAll() {
Cache::increment($this->versionKey);
}
}
最佳实践建议
选择合适的过期策略
// 对于不常变化的数据(如配置)
Cache::set('site_config', $config, 86400); // 24小时
// 对于用户会话数据
Cache::set("session:$userId", $session, 1800); // 30分钟
// 对于统计数据
Cache::set('daily_stats', $stats, 300); // 5分钟更新
监控缓存命中率
class MonitoredCache {
private $hits = 0;
private $misses = 0;
public function get($key) {
$data = parent::get($key);
if ($data === null) {
$this->misses++;
} else {
$this->hits++;
}
return $data;
}
public function getHitRate() {
$total = $this->hits + $this->misses;
return $total > 0 ? ($this->hits / $total) * 100 : 0;
}
}
错误处理
function getWithFallback($key, $callback, $ttl = 3600) {
try {
$data = Cache::get($key);
if ($data !== null) {
return $data;
}
} catch (\Exception $e) {
// 缓存系统不可用时,直接查询数据库
Log::warning('Cache unavailable, falling back to DB');
}
return $callback();
}
- 80%的场景:使用简单的 TTL + 懒加载模式
- 高并发场景:需要加锁机制防止缓存雪崩
- 数据一致性要求高:使用 Write-Through 模式
- 大规模系统:考虑二级缓存 + 版本控制
选择方案时要考虑:
- 数据更新频率
- 数据一致性要求
- 系统并发量
- 缓存资源成本
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播