使用redis缓存接口数据并设置过期时间,核心做法是先通过 get 方法查询缓存中是否存在目标键值。如果存在且未过期,直接返回该数据;如果不存在或已过期,则执行数据库查询获取最新数据,随后调用 setex 方法将数据存入redis并指定过期秒数。这样做既能保证后续请求快速响应,又能确保数据在设定周期后自动失效,避免脏数据长期驻留。

如何判断缓存是否命中并处理空值情况?
在实现逻辑中,必须区分“缓存未命中”与“数据库中无数据”两种状态。如果直接使用 setex 存储空结果(如 false 或空数组),会导致正常业务数据被错误地标记为过期,引发雪崩或频繁穿透数据库的问题。正确的做法是检查数据库查询的返回值,仅当确实获取到有效数据时才写入缓存,或者针对空值使用专门的短时效策略进行隔离。

<?php $redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'api_user_data';
$expireTime = 3600; // 1小时
// 1. 尝试从缓存获取
$data = $redis->get($key);
if ($data !== false) {
// 缓存命中,直接返回
echo json_encode(['status' => 'hit', 'data' => unserialize($data)]);
} else {
// 2. 缓存未命中,查询数据库(模拟)
$dbData = fetchFromDatabase();
if ($dbData !== null && !empty($dbData)) {
// 3. 有数据,写入缓存并设置过期时间
$serialized = serialize($dbData);
$redis->setex($key, $expireTime, $serialized);
echo json_encode(['status' => 'miss', 'data' => $dbData]);
} else {
// 4. 数据库也无数据,可选择缓存空值防止穿透
$redis->setex($key, 60, ''); // 短时效缓存空值
echo json_encode(['status' => 'empty', 'data' => null]);
}
}
function fetchFromDatabase() {
// 模拟数据库返回
return ['id' => 1, 'name' => 'Test User'];
}
?>
如何确保高并发下缓存更新的原子性?
在高并发场景下,多个请求可能同时发现缓存失效,从而同时发起数据库查询,导致“缓存击穿”。虽然 setex 本身是原子操作,但它无法解决并发写入冲突。更稳健的做法是使用 setnx(SET If Not Exists)配合 expire,或者利用Redis的分布式锁机制。这里展示一种简化的基于 setnx 的单点更新策略:只有第一个获取到锁的请求才去查库并更新缓存,其他请求等待或重试。

<?php $redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'api_lock_key';
$dataKey = 'api_user_data';
$lockExpire = 5; // 锁持有时间5秒
$dataExpire = 3600;
// 尝试获取锁
$isLocked = $redis->set($key, 'locked', ['nx', 'ex' => $lockExpire]);
if ($isLocked) {
try {
// 双重检查:获取锁后再次确认缓存是否已被其他线程填充
$data = $redis->get($dataKey);
if ($data === false) {
// 执行耗时操作:查库
$dbData = fetchFromDatabase();
if ($dbData) {
$redis->setex($dataKey, $dataExpire, serialize($dbData));
}
}
} finally {
// 释放锁
$redis->del($key);
}
}
// 无论是否加锁成功,最终都读取当前缓存
$result = $redis->get($dataKey);
echo $result ? unserialize($result) : 'No Data';
?>
当接口参数变化时,如何设计合理的缓存键?
缓存键的设计直接决定了数据的准确性。如果接口支持分页、排序或多条件筛选,简单的固定键名会导致数据混淆。例如,用户A请求第1页和用户B请求第2页,如果使用相同的键 api_users,后者会覆盖前者的缓存。因此,必须将关键查询参数(如 page, sort, filter_id)哈希或拼接进键名中,形成唯一的标识符,确保不同条件的请求互不干扰。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











