Medoo框架Redis缓存键不匹配问题的解决方法咨询
解决Medoo结合Redis缓存时更新/删除无法清除对应缓存的问题
问题根源
你当前只靠$table和$where生成缓存键,存在几个致命问题:
- 忽略了select方法里的
$join、$columns参数,这俩会直接影响查询结果,没加入键的生成逻辑会导致缓存键不唯一 json_encode对数组键的顺序敏感,比如select时$where是['id' => 1, 'status' => 1],update时写成['status' => 1, 'id' => 1],md5结果完全不一样- Medoo的
$where支持多种格式(数组、字符串、嵌套条件),如果update/delete时传入的格式和select不一致,也会导致键不匹配
具体解决办法
1. 统一缓存键生成规则,覆盖所有影响查询的参数
把select里的$join、$columns都加入键的生成,同时对所有数组参数做键排序,避免顺序问题:
// 抽成通用的缓存键生成函数 private function generateCacheKey(string $table, $join, $columns, $where): string { // 递归归一化数组:排序键,处理嵌套数组 $normalize = function ($param) use (&$normalize) { if (is_array($param)) { ksort($param); foreach ($param as &$val) { $val = $normalize($val); } unset($val); } return $param; }; $normalizedData = [ 'table' => $table, 'join' => $normalize($join), 'columns' => $normalize($columns), 'where' => $normalize($where) ]; return md5(json_encode($normalizedData)); } // 在你的select方法里调用 public function select(string $table, $join, $columns = null, $where = null): ?array { $redisKey = $this->generateCacheKey($table, $join, $columns, $where); // 后续Redis读取/写入缓存的逻辑... }
2. 按表批量清除缓存(简单高效)
更新或删除时,没法直接复用select的完整参数,最简单的方式是给缓存键加上表前缀,然后批量删除对应表的所有缓存:
// 修改缓存键生成,加上表前缀 private function generateCacheKey(string $table, $join, $columns, $where): string { // 保留上面的归一化逻辑... $normalizedData = [...]; return "cache:{$table}:" . md5(json_encode($normalizedData)); } // 重写update方法 public function update(string $table, $data, $where = null): bool { // 先执行原Medoo的更新操作 $result = parent::update($table, $data, $where); // 清除该表下所有缓存键(生产环境建议用SCAN替代KEYS,避免阻塞) $keys = $this->redis->keys("cache:{$table}:*"); if (!empty($keys)) { $this->redis->del($keys); } return $result; } // delete方法同理 public function delete(string $table, $where = null): bool { $result = parent::delete($table, $where); $keys = $this->redis->keys("cache:{$table}:*"); if (!empty($keys)) { $this->redis->del($keys); } return $result; }
3. 精细清除受影响的缓存(可选)
如果按表清除粒度太大,想只删受影响的查询缓存,可以用Redis的集合存储缓存键和where的映射:
// select时存储映射关系 public function select(string $table, $join, $columns = null, $where = null): ?array { $redisKey = $this->generateCacheKey($table, $join, $columns, $where); $normalizedWhere = $this->normalize($where); $mapKey = "cache:map:{$table}:" . md5(json_encode($normalizedWhere)); // 把当前缓存键加入对应where的集合 $this->redis->sAdd($mapKey, $redisKey); // 后续缓存逻辑... } // update时清除对应缓存 public function update(string $table, $data, $where = null): bool { $result = parent::update($table, $data, $where); $normalizedWhere = $this->normalize($where); $mapKey = "cache:map:{$table}:" . md5(json_encode($normalizedWhere)); // 获取该where对应的所有缓存键并删除 $keys = $this->redis->sMembers($mapKey); if (!empty($keys)) { $this->redis->del($keys); $this->redis->del($mapKey); } return $result; }
内容的提问来源于stack exchange,提问作者Richard R. Hollis
相关产品推荐
相关产品推荐

