T5清理redis或file缓中带tag的指定缓存
前置条件
项目接口中使用了缓存记录冷数据,然后在后台管理界面中提供了手动管理缓存的功能,可删除指定key的缓存或者批量删除。
正文
下面是一个简单事例
接口controller中使用带tag缓存
public function getCategories(){
$data=Cache::tag(CACHE_TAG)->get(CACHE_CATEGORIES);
if($data==null){
$data = Db::name('category')
->where('status',1)
->select();
Cache::tag(CACHE_TAG)->set(CACHE_CATEGORIES,$data,3600*24*30);
}
return $data;
}
后台管理缓存
缓存数据初始页面
public function cache(){
//加载application下的配置
$configuration = Config::load(APP_PATH.'config.php');
$type=$configuration['cache']['type'];
//缓存中使用了tag,此处获取tag值,在redis服务器中可以查看到该tag包含的所有缓存键
$key = 'tag_' . md5(CACHE_TAG);
//此处使用application下的cache配置,如果直接使用Cache::get方法,加载的cache来自后台config.php所定的缓存类型
//目的是为了解决application与后台配置的缓存类型不同,导致加载出错
$value = Cache::connect($configuration['cache'])->get($key);
$tagKeys = array_filter(explode(',', $value));
$data = [];
//redis缓存的处理
if('redis'==strtolower($type)) {
foreach ($tagKeys as $id => $key) {
$data[$id]['sequence'] = $id + 1;
$data[$id]['key'] = $key;
$value = Cache::tag(CACHE_TAG)->get($key);
$data[$id]['value'] = $value ? json_encode($value, JSON_UNESCAPED_UNICODE) : '';
}
}
//file缓存处理
if('file'==strtolower($type)) {
foreach ($tagKeys as $id => $key) {
$data[$id]['sequence'] = $id + 1;
$data[$id]['key'] = $key;
$value = file_get_contents($key);
$content = unserialize(substr($value, 32));
$data[$id]['value'] = $value ? json_encode($content, JSON_UNESCAPED_UNICODE) : '';
}
}
$this->assign(['tag'=>CACHE_TAG,'list'=>$data]);
return $this->fetch('cache');
}
删除缓存操作方法
public function clearCache(){
$input=input('get.');
$configuration = Config::load(APP_PATH.'config.php');
$type=$configuration['cache']['type'];
//目前只做redis/file的缓存类型
if('redis'!=strtolower($type) && 'file'!=strtolower($type)){
echo '<script>alert("缓存类型不是redis或者file,不支持删除")</script>';
return $this->cache();
}
try{
$tagKey = 'tag_' . md5(CACHE_TAG);
$tagValue = Cache::connect($configuration['cache'])->get($tagKey);
//清除tag相关的所有缓存
if(!empty($input['tag'])){
Cache::clear(CACHE_TAG);
}
//清除单个或多个缓存
if(!empty($input['key'])){
if(is_array($input['key'])){
foreach ($input['key'] as $key){
if('redis'==strtolower($type)) {
Cache::tag(CACHE_TAG)->rm($key);
}elseif ('file'==strtolower($type)){
unlink($key);
}
$tagValue=str_replace($key,'',$tagValue);
}
}else{
if('redis'==strtolower($type)) {
Cache::tag(CACHE_TAG)->rm($input['key']);
}elseif ('file'==strtolower($type)){
unlink($input['key']);
}
$tagValue=str_replace($input['key'],'',$tagValue);
}
$tagArray=array_filter(explode(',',$tagValue));
Cache::set($tagKey,implode(',',$tagArray));
}
echo '<script>alert("成功删除缓存")</script>';
return $this->cache();
}catch (\Exception $e){
echo '<script>alert("删除缓存失败")</script>';
return $this->cache();
}
}
视图页面
<div style="padding-top: 15px;">
<a href="{:url('clearCache',array('tag'=>$tag))}"><span class="layui-btn layui-btn-normal">清除全部缓存</span></a>
</div>
<form action="{:url('clearCache')}" method="GET">
<select name="choose" id="choose" onchange="chooseKey(this.value)">
<option value="0"></option>
<option value="1">全选</option>
<option value="2">反选</option>
<option value="3">取消选中</option>
</select>
<button id="sub">清除选中的缓存</button>
<table class="table-hover">
<thead>
<tr>
<th style="width: 5%"></th>
<th style="width: 5%">sequence</th>
<th style="width: 20%">key</th>
<th style="width: 60%">value</th>
<th style="width: 10%">Action</th>
</tr>
</thead>
<tbody>
{volist name='list' id='vo'}
<tr>
<td style="width: 5%">
<input type="checkbox" name="key[]" id="key" value="{$vo.key}">
</td>
<td style="width: 5%">{$vo.sequence}</td>
<td style="width: 20%">{$vo.key}</td>
<td style="width: 60px">{$vo.value}</td>
<td style="width: 10%"><a href="{:url('clearCache',array('key'=>$vo.key))}"><span class="btn">删除</span></a></td>
</tr>
{/volist}
</tbody>
</table>
</form>
<script>
function chooseKey(value){
var key=document.getElementsByName("key[]");
//全选中
if(value==1){
for(var i=0;i<key.length;i++){
key[i].checked=true;
}
} else if(value==2){
///反向选择
for(var i=0;i<key.length;i++){
key[i].checked=!key[i].checked;
}
} else if(value==3) {
//全不选
for (var i = 0; i < key.length; i++) {
key[i].checked = false;
}
} else{
}
}
</script>
不过上面对于file类型的缓存存在一个显示的问题,即UI 显示的key列是文件路径,而不是缓存的键,tp5中文件驱动类型think\cache\driver\File::getCacheKey()中通过缓存键获取缓存的文件路径,但不清楚文件缓存是怎么获取所有key。