cache::get()返回null不表示未命中,可能是值本身就是null;应使用has()+get()组合或底层驱动方法区分,批量删除需用标签机制而非通配符,remember闭包需防异常和副作用,array驱动不可用于生产环境。

缓存读取失败时,Cache::get() 返回 null 不代表没命中
这是最常被误解的一点:当 Cache::get('key') 返回 null,可能是缓存里真没这个 key,也可能是你存进去的值本身就是 null。Laravel 的底层(比如 Redis、File)不区分“未命中”和“命中 null 值”,一律返回 null。
实操建议:
- 存值前主动过滤或包装,比如用
Cache::put('key', ['value' => $data])避免原始null - 改用
Cache::has('key')+Cache::get('key')组合判断,但注意这存在竞态风险(尤其在高并发写场景) - 如果必须区分,用
Cache::store('redis')->get('key')直接调底层驱动方法(如 Redis 的GET),部分驱动支持原生响应
删除缓存用 Cache::forget(),但要注意通配符不生效
Laravel 默认缓存驱动(包括 file、database、array)都不支持通配符删除,Cache::forget('user_*') 会静默失败,什么也不删。
常见错误现象:清用户相关缓存时写 Cache::forget('user_'.$id) 是对的,但想批量清 user_* 就不行。
实操建议:
- 用标签(tags)机制替代通配符:
Cache::tags(['user'])->put('profile', $data, 3600),然后Cache::tags(['user'])->flush() - 仅限支持标签的驱动:Redis、Memcached、DynamoDB;
file和database驱动不支持tags,启用会报错Method tags does not exist - 若必须用 file 驱动批量删,得手动遍历
storage/framework/cache/data/目录匹配文件名 —— 不推荐,易出错且非原子操作
Cache::remember() 的闭包执行时机和异常处理容易被忽略
Cache::remember('key', 3600, function () { return DB::table('users')->get(); }) 看似简单,但闭包只在缓存 miss 时执行,且一旦抛异常,整个缓存不会写入,下次还会再进闭包 —— 这可能触发重复 DB 查询或 API 调用。
使用场景:适合读多写少、数据稳定、失败代价低的操作。
实操建议:
- 闭包内加 try/catch,兜底返回默认值,避免反复失败:
return $e ? collect([]) : $result - 不要在闭包里做副作用操作(如发邮件、改数据库),因为执行不可控(可能多次、可能不执行)
- 若需强制刷新缓存,用
Cache::flush()或直接Cache::forget('key')后再调一次remember,别依赖过期时间硬等
本地开发用 array 缓存驱动,上线切 redis 时要检查序列化兼容性
array 驱动只是内存数组,不序列化;而 redis、memcached 必须序列化 PHP 值。如果缓存对象含闭包、资源句柄或未实现 __serialize() 的自定义类,上线后会报 Serialization of 'Closure' is not allowed。
性能影响:array 驱动每次请求重置,根本不算“缓存”,仅用于调试;redis 有网络开销,但支持跨请求、跨进程共享。
实操建议:
- 本地开发时,在
.env设CACHE_DRIVER=array,但测试阶段务必切到redis跑一遍缓存路径 - 存对象前先
var_dump(serialize($obj))测试是否可序列化;含 Laravel Model 的,优先存$model->toArray()或$model->toJson() - 避免缓存
Request、Response、UploadedFile等框架内部对象,它们通常不可序列化
Cache::remember 很容易埋下数据不一致的坑。最麻烦的从来不是怎么写,而是怎么精准地失效。










