清缓存本身是一个很简单的操作,但其中也有些学问。
一. 最简单版
最常见的清缓存是这么写的:
function clearCache() {
$Memcache->delete($key);
}
二. 延迟版
但当主从同步延迟的时候,这样写请求如果有个查询立即读取db,就可能把旧数据存到缓存里。于是有了升级版:
function clearCacheByDelay() {
$data = $Memcache->get($key);
if ($data) {
return $Memcache->set($key, $data, 2);
}
return true;
}
这个版本会获取缓存数据,如果缓存还在,就让原来的缓存保持2秒后过期,这样2秒后缓存过期,从db读取时就能取到新数据了
三. 部分更新版
但是当写入量巨大的地方,用前两种方案会导致缓存反复丢失,于是有了只更新缓存中某个字段的部分更新版:
这版本原理是从新数据中提取某个字段,更新到当前的缓存中,存长期
public function updateMultiUserCacheByKey($data, $key = null) {
if (!$data) {
return false;
}
$ids = array_keys($data);
$cache_data = $this->getMultiCache($ids);
if ($cache_data) {
foreach ($cache_data as $_id => $_data) {
if ($key) {
if (isset($data[$_id][$key])) {
$cache_data[$_id][$key] = $data[$_id][$key];
}
} else {
$cache_data[$_id] = $data[$_id];
}
}
$this->setMultiCache($cache_data);
}
return true;
}
四. 异常 & 修复
最近发现一个问题,当延迟版先执行,部分更新版后执行的时候,就会出问题:
延迟版并没有更新数据,只是保留旧数据,让旧数据2秒后更新。
而部分更新版反其道行之,会在当前数据基础上修改字段,然后存长期
二者同时执行就有可能在旧数据修改了某字段的基础上存长期,导致缓存错误。
这种情况最好就要将两个版本进行一个兼容:
延迟版增加一个临时缓存的标记:
function clearCacheByDelay() {
$data = $Memcache->get($key);
if ($data) {
$data[‘is_temp_cache’] = 1;
return $Memcache->set($key, $data, 2);
}
return true;
}
部分更新版忽略临时缓存的数据:
public function updateMultiUserCacheByKey($data, $key = null) {
if (!$data) {
return false;
}
$ids = array_keys($data);
$cache_data = $this->getMultiCache($ids);
if ($cache_data) {
foreach ($cache_data as $_id => $_data) {
if ($_data[‘is_temp_cache’]) {
unset($cache_data[$_uid]);
continue;
}
if ($key) {
if (isset($data[$_id][$key])) {
$cache_data[$_id][$key] = $data[$_id][$key];
}
} else {
$cache_data[$_id] = $data[$_id];
}
}
$this->setMultiCache($cache_data);
}
return true;
}