数字化技能提升教程,数字化时代生存宝典

Laravel缓存

浏览:119

文章分类、导航菜单和系统设置通常读取频繁、修改较少。如果每次打开页面都查询数据库,会产生不少重复操作。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

QQ群号:4114653

温馨提示:
  1. 本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。邮箱:2942802716#qq.com(#改为@)。
  2. 本站原创内容未经允许不得转载,转载请注明出处“站长百科”和原文地址。