Laravel缓存
文章分类、导航菜单和系统设置通常读取频繁、修改较少。如果每次打开页面都查询数据库,会产生不少重复操作。Laravel Cache 可以把这些查询结果暂存起来,在有效期内重复使用,减少数据库访问。
下面以文章分类列表为例,介绍缓存的读取、写入、过期和主动清理。示例采用 Laravel 11、12 常见配置,假设项目已经存在 Category 模型,以及包含 id、name、slug 字段的 categories 表。
一、选择缓存存储
Laravel 缓存配置位于:
config/cache.php
新版本项目通常通过 .env 中的 CACHE_STORE 选择默认存储。
本地入门可以先用文件缓存:
CACHE_STORE=file
团队共享缓存或多服务器部署可以使用 Redis:
CACHE_STORE=redis
Redis 需要提前配置连接和 PHP 客户端。文件缓存只保存在当前服务器,多节点部署时不会自动同步。
旧项目可能使用 CACHE_DRIVER,应检查 config/cache.php 实际读取的环境变量,不能只修改变量名称。
修改配置后,开发环境可执行:
php artisan config:clear
生产部署如果使用配置缓存,则应重新生成配置缓存,并让相关长驻进程加载新配置。
二、缓存查询结果
在控制器中使用 Cache::remember():
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use Illuminate\Support\Facades\Cache;
class CategoryController extends Controller
{
public function index()
{
$categories = Cache::remember(
'categories:list:v1',
now()->addMinutes(10),
function () {
return Category::query()
->select(['id', 'name', 'slug'])
->orderBy('id')
->get();
}
);
return response()->json($categories);
}
}
第一次访问时,如果缓存不存在,Laravel 会执行查询,并把返回结果保存 10 分钟。
后续访问只要命中缓存,就不会再次执行这个查询回调。缓存过期后,下一次请求会重新查询并写入新缓存。
缓存查询结果前,仍应先确认 SQL 和索引合理。缓存不能替代基础查询优化;模型查询相关内容可以结合站长百科的 Laravel教程继续学习。
三、常用缓存操作
写入缓存:
Cache::put('site:notice', '系统维护已完成', now()->addMinutes(5));
读取缓存:
$notice = Cache::get('site:notice');
缓存不存在时返回默认值:
$notice = Cache::get('site:notice', '');
删除指定缓存:
Cache::forget('site:notice');
只有缓存键不存在时才写入:
$added = Cache::add(
'reports:daily:pending',
true,
now()->addMinutes(5)
);
add() 会返回是否写入成功,适合部分简单的状态标记场景。需要保护关键并发操作时,应使用缓存锁或数据库约束,不能只靠普通的“先检查、再写入”。
四、数据更新后主动清理缓存
分类改名后,如果只更新数据库,用户可能仍会看到缓存中的旧名称。对于修改频率较低的列表,常见做法是数据库更新成功后删除对应缓存。
use App\Models\Category;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
public function update(Request $request, Category $category)
{
$data = $request->validate([
'name' => ['required', 'string', 'max:100'],
]);
$category->update($data);
Cache::forget('categories:list:v1');
return response()->json([
'message' => '分类已更新',
'data' => $category,
]);
}
这段示例用于已配置登录和分类修改权限的后台路由。参数验证只检查输入是否符合要求,不能替代用户授权。
删除缓存后,下一次读取列表时会查询新数据,并重新建立缓存。新增、删除分类时,也应清理相同的列表缓存。
如果更新放在数据库事务中,应在事务提交成功后清理缓存,避免其他请求在事务尚未提交时重新缓存旧数据。高并发下仍可能出现短暂不一致,因此这种方式适合允许短时延迟的分类、导航等数据。
五、合理设计缓存键
缓存键应清楚表达数据范围。一个固定键只能用于固定查询条件,不能让不同页面、用户或筛选条件共用同一份结果。
例如缓存文章分页:
$page = max(1, (int) request('page', 1));
$cacheKey = "posts:published:page:{$page}:v1";
如果查询还包含分类、语言、每页条数等条件,缓存键也要包含这些条件。
用户专属数据更要区分身份,例如:
$cacheKey = "users:{$user->id}:dashboard:v1";
多租户项目还应包含租户标识。缓存中保存了不同权限范围的数据时,即使接口有登录检查,也不能把同一份结果返回给所有用户。
六、设置有效期与清理策略
缓存有效期应取决于业务允许的数据延迟。
分类列表和导航菜单可以设置几分钟有效期,并在后台修改后主动删除。变化较快的数据应使用更短有效期,或直接读取数据库。
价格、库存、支付状态等数据需要格外谨慎。展示页面可以在业务允许时使用缓存,但下单、扣库存和支付确认必须以可信的业务状态为准。
不设置到期时间的缓存可以使用:
Cache::forever('site:settings:v1', $settings);
这种写法需要可靠的主动清理机制。部分缓存后端还可能因为容量限制而淘汰数据,所以应用仍应能处理缓存不存在的情况。
七、如何确认缓存生效
在测试环境临时给查询回调添加日志:
$categories = Cache::remember(
'categories:list:v1',
now()->addMinutes(10),
function () {
logger()->debug('分类缓存未命中,开始查询数据库');
return Category::query()
->select(['id', 'name', 'slug'])
->orderBy('id')
->get();
}
);
清理这个键后连续访问接口。如果首次请求产生日志、后续请求没有重复日志,通常说明缓存已经命中。
同时应验证修改分类后缓存会失效,新名称能够显示。检查完毕后,可以移除临时调试日志。
八、常见问题
缓存过期后,会立刻重新查询数据库吗?
不会。remember() 通常在下一次请求读取该键时发现缓存不可用,才执行查询回调。它不会自动在后台刷新数据。
cache:clear 和 config:clear 有什么区别?
cache:clear 用于清理应用缓存,config:clear 用于清除配置缓存。修改 .env 后配置没有生效,应检查配置缓存和长驻进程,而不只是清理业务缓存。
可以用 Cache::flush() 清理一个模块吗?
不适合。flush() 会清理所选缓存存储中的全部缓存,而且不遵循应用配置的缓存前缀。多个应用共享同一存储时可能互相影响,模块更新应优先使用 forget() 删除指定键。
多个请求同时遇到缓存过期会怎样?
它们可能同时执行查询回调。remember() 本身不保证同一时间只有一个请求重建缓存。对重建成本高的热点数据,需要进一步使用原子锁、预热等措施。
广告合作
QQ群号:4114653
- 本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。邮箱:2942802716#qq.com(#改为@)。
- 本站原创内容未经允许不得转载,转载请注明出处“站长百科”和原文地址。