Laravel文件驱动缓存:通过键片段匹配查询缓存值的方法
在Laravel文件驱动缓存中实现按键片段匹配查找
嘿,我完全懂你想实现的需求——就像SQL里用like '%{segment}%'那样,通过缓存键的片段找到对应的缓存值,而且你现在用的是文件驱动。刚好我之前也遇到过类似的场景,给你分享两个可行的方案:
方案一:直接遍历缓存文件解析(适合小缓存量)
Laravel的文件驱动缓存,每个缓存项都存在storage/framework/cache/data目录下的独立文件里。虽然文件名是缓存键的哈希值,但文件内容里会保存原始的缓存键、序列化后的值和过期时间,格式是{原始键}|{序列化值}|{过期时间}。我们可以遍历这些文件,解析出原始键进行匹配:
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\File; function findCacheByKeySegment(string $segment): array { // 获取文件缓存的存储实例和目录路径 $store = Cache::store('file')->getStore(); $cacheDir = $store->getDirectory(); $matchingItems = []; // 遍历目录下所有缓存文件 foreach (File::allFiles($cacheDir) as $file) { $content = File::get($file); // 按|分割内容,提取原始缓存键 $parts = explode('|', $content, 3); if (count($parts) < 2) { continue; // 跳过格式异常的文件 } $cacheKey = $parts[0]; // 检查键是否包含目标片段 if (str_contains($cacheKey, $segment)) { // 反序列化获取缓存值 $value = unserialize($parts[1]); $matchingItems[$cacheKey] = $value; } } return $matchingItems; }
优缺点
- ✅ 不需要额外配置或修改现有代码,直接可用
- ❌ 缓存文件较多时,遍历解析会很慢,性能差,只适合缓存量小的场景
方案二:维护缓存键索引(适合大缓存量)
如果你的缓存项比较多,遍历文件的方式就不太高效了。这时候可以提前维护一个缓存键的索引集合,把所有缓存键存在一个固定的缓存项里,查找时先从索引里筛选匹配的键,再批量获取对应的值。
方式1:手动维护索引(简单直接)
在设置缓存的时候,同步更新索引:
use Illuminate\Support\Facades\Cache; // 封装带索引的缓存设置方法 function setCacheWithIndex(string $key, $value, $ttl = null) { Cache::put($key, $value, $ttl); // 更新索引:把新键加入索引数组 $index = Cache::get('cache_keys_index', []); if (!in_array($key, $index)) { $index[] = $key; // 索引可以设为永久有效,或者比所有缓存项的过期时间更长 Cache::forever('cache_keys_index', $index); } } // 根据片段查找缓存 function findCacheByKeySegment(string $segment): array { $index = Cache::get('cache_keys_index', []); // 筛选包含目标片段的键 $matchingKeys = array_filter($index, fn($key) => str_contains($key, $segment)); // 批量获取缓存值,比逐个获取更高效 return Cache::many($matchingKeys); }
方式2:用缓存事件自动维护索引(更优雅)
手动修改所有设置缓存的地方太麻烦?可以利用Laravel的缓存事件,自动在缓存键被写入或删除时更新索引:
- 注册事件监听器
在app/Providers/EventServiceProvider.php里添加监听:
protected $listen = [ \Illuminate\Cache\Events\KeyWritten::class => [ \App\Listeners\UpdateCacheKeyIndex::class, ], \Illuminate\Cache\Events\KeyDeleted::class => [ \App\Listeners\RemoveCacheKeyFromIndex::class, ], ];
- 创建写入事件监听器
生成UpdateCacheKeyIndex类:
namespace App\Listeners; use Illuminate\Cache\Events\KeyWritten; use Illuminate\Support\Facades\Cache; class UpdateCacheKeyIndex { public function handle(KeyWritten $event) { $index = Cache::get('cache_keys_index', []); if (!in_array($event->key, $index)) { $index[] = $event->key; Cache::forever('cache_keys_index', $index); } } }
- 创建删除事件监听器
生成RemoveCacheKeyFromIndex类:
namespace App\Listeners; use Illuminate\Cache\Events\KeyDeleted; use Illuminate\Support\Facades\Cache; class RemoveCacheKeyFromIndex { public function handle(KeyDeleted $event) { $index = Cache::get('cache_keys_index', []); if (($position = array_search($event->key, $index)) !== false) { unset($index[$position]); // 重新索引数组,避免空键 Cache::forever('cache_keys_index', array_values($index)); } } }
这样不管是用Cache::put()、Cache::forever()还是其他方法设置缓存,索引都会自动更新,删除缓存时也会同步移除索引里的键,完全不用手动干预。
优缺点
- ✅ 查找速度极快,适合缓存量大的场景
- ✅ 自动维护索引后,无需修改现有业务代码
- ❌ 需要额外维护索引,会占用一点缓存空间
总结
如果你的缓存项数量不多,方案一的遍历方式足够简单好用;如果缓存量较大,推荐用方案二的索引方式,性能提升很明显。
内容的提问来源于stack exchange,提问作者Omar Ajmi
相关产品推荐
相关产品推荐

