什么是缓存
数据库查询、外部 API 调用等操作 CPU 与网络成本高,可能耗时数秒。
如果反复获取相同数据,可以把结果保存到缓存 ,后续请求就能高速处理。
Laravel 提供了统一 API,支持 Memcached、Redis、DynamoDB、数据库等多种缓存后端。
默认使用 database 驱动。切换到 Redis 或 Memcached 可获得更高性能。
缓存配置
config/cache.php
缓存配置集中在 config/cache.php。通过 CACHE_STORE 环境变量选择默认驱动:
// config/cache.php
'default' => env ( 'CACHE_STORE' , 'database' ),
可用驱动
将序列化后的缓存数据保存到数据库表。Laravel 11 及以上的新项目已包含迁移。 如无迁移可使用: php artisan make:cache-table
php artisan migrate
内存中高速缓存,生产环境最常用。需要 PhpRedis 扩展或 predis/predis。 CACHE_STORE =redis
REDIS_HOST =127.0.0.1
REDIS_PORT =6379
需要 Memcached PECL 扩展。在 config/cache.php 中配置服务器: 'memcached' => [
'servers' => [
[
'host' => env ( 'MEMCACHED_HOST' , '127.0.0.1' ),
'port' => env ( 'MEMCACHED_PORT' , 11211 ),
'weight' => 100 ,
],
],
],
使用 AWS DynamoDB。需先创建表并安装 AWS SDK: composer require aws/aws-sdk-php
CACHE_STORE =dynamodb
DYNAMODB_CACHE_TABLE =cache
AWS_DEFAULT_REGION =us-east-1
AWS_ACCESS_KEY_ID =your-key-id
AWS_SECRET_ACCESS_KEY =your-secret-key
将任意 Filesystem 磁盘作为键值缓存。适合直接复用已有 S3 磁盘: 'storage' => [
'driver' => 'storage' ,
'disk' => env ( 'CACHE_STORAGE_DISK' ),
'path' => env ( 'CACHE_STORAGE_PATH' , 'framework/cache/data' ),
],
array 只在请求内有效,null 忽略所有操作。用于自动化测试。
缓存驱动层次
基本操作
获取 Cache 门面
<? php
namespace App\Http\Controllers ;
use Illuminate\Support\Facades\ Cache ;
class UserController extends Controller
{
public function index () : array
{
$value = Cache :: get ( 'key' );
return [
// ...
];
}
}
多个存储切换:
$value = Cache :: store ( 'file' ) -> get ( 'foo' );
Cache :: store ( 'redis' ) -> put ( 'bar' , 'baz' , 600 ); // 10 分钟
取值:Cache::get()
不存在时返回 null,可指定默认值。
$value = Cache :: get ( 'key' );
$value = Cache :: get ( 'key' , 'default' );
$value = Cache :: get ( 'key' , function () {
return DB :: table ( 'settings' ) -> get ();
});
存值:Cache::put()
// 10 秒
Cache :: put ( 'key' , 'value' , 10 );
// Carbon
Cache :: put ( 'key' , 'value' , now () -> plus ( minutes : 10 ));
// 永久
Cache :: put ( 'key' , 'value' );
只在键不存在时存入用 add()(原子操作):
Cache :: add ( 'key' , 'value' , $seconds );
永久存储:
Cache :: forever ( 'key' , 'value' );
取或存:Cache::remember()
最常用的方式 。若缓存中已有则返回,无则运行闭包并存回。
$users = Cache :: remember ( 'users' , 3600 , function () {
return DB :: table ( 'users' ) -> get ();
});
Cache::remember() 一行即可完成「查缓存 → 未命中则取 → 写入缓存」的三步。数据库查询与外部 API 响应缓存都适用。
remember() 流程
永久存储版本:
$value = Cache :: rememberForever ( 'users' , function () {
return DB :: table ( 'users' ) -> get ();
});
若需要知道数据是否来自缓存,可用 rememberWithWarmth():
[ $value , $warm ] = Cache :: rememberWithWarmth ( 'users' , 3600 , function () {
return DB :: table ( 'users' ) -> get ();
});
if ( $warm ) {
// 来自缓存
} else {
// 刚从闭包取回
}
Stale While Revalidate
Cache::flexible() 指定「新鲜期」和「可容忍陈旧期」两个时长,向用户返回旧数据的同时后台刷新缓存:
$value = Cache :: flexible ( 'users' , [ 5 , 10 ], function () {
return DB :: table ( 'users' ) -> get ();
});
存在性检查
if ( Cache :: has ( 'key' )) {
// 已存在
}
Cache :: add ( 'key' , 0 , now () -> addHours ( 4 ));
Cache :: increment ( 'key' );
Cache :: increment ( 'key' , $amount );
Cache :: decrement ( 'key' );
Cache :: decrement ( 'key' , $amount );
取出后删除:Cache::pull()
$value = Cache :: pull ( 'key' );
删除:Cache::forget()
Cache :: forget ( 'key' );
Cache :: flush ();
Cache::flush() 会忽略「前缀」设置删除全部条目。多应用共用缓存时请谨慎。
Cache::flushLocks() 可清理所有原子锁。
延长 TTL:Cache::touch()
Cache :: touch ( 'key' , 3600 );
Cache :: touch ( 'key' , now () -> addHours ( 2 ));
缓存 memoization
memo 驱动会在同一请求内把缓存值缓存到内存,减少对存储的往返:
use Illuminate\Support\Facades\ Cache ;
$value = Cache :: memo () -> get ( 'key' );
$value = Cache :: memo ( 'redis' ) -> get ( 'key' );
$value = Cache :: memo () -> get ( 'key' ); // 访问存储
$value = Cache :: memo () -> get ( 'key' ); // 从内存返回
缓存标签
将相关缓存分组,可整体删除。
file、dynamodb、database、storage 驱动不支持缓存标签。需 redis 或 memcached。
use Illuminate\Support\Facades\ Cache ;
Cache :: tags ([ 'people' , 'artists' ]) -> put ( 'John' , $john , $seconds );
Cache :: tags ([ 'people' , 'authors' ]) -> put ( 'Anne' , $anne , $seconds );
$john = Cache :: tags ([ 'people' , 'artists' ]) -> get ( 'John' );
$anne = Cache :: tags ([ 'people' , 'authors' ]) -> get ( 'Anne' );
Cache :: tags ([ 'people' , 'authors' ]) -> flush ();
Cache :: tags ( 'authors' ) -> flush ();
按用户或文章分组失效缓存时非常有用。例如 Cache::tags(['user', "user:{$userId}"])->flush() 清除该用户相关的所有缓存。
原子操作(锁)
Cache::lock() 可实现分布式锁,避免并发冲突。
该功能在 memcached、redis、dynamodb、database、file、array 驱动中可用。所有服务器需连接同一中心缓存服务器。
基础锁
use Illuminate\Support\Facades\ Cache ;
$lock = Cache :: lock ( 'foo' , 10 );
if ( $lock -> get ()) {
// 加锁成功(10 秒有效)
$lock -> release ();
}
传闭包会在结束时自动释放:
Cache :: lock ( 'foo' , 10 ) -> get ( function () {
// 自动释放
});
等待锁
use Illuminate\Contracts\Cache\ LockTimeoutException ;
$lock = Cache :: lock ( 'foo' , 10 );
try {
$lock -> block ( 5 ); // 最多等 5 秒
// 处理...
} catch ( LockTimeoutException $e ) {
// 获取失败
} finally {
$lock -> release ();
}
或用闭包:
Cache :: lock ( 'foo' , 10 ) -> block ( 5 , function () {
// 最多等 5 秒,结束后自动释放
});
防止重复执行:withoutOverlapping()
Cache :: withoutOverlapping ( 'foo' , function () {
// 同时只有一个在运行
});
Cache :: withoutOverlapping ( 'foo' , function () {
// ...
}, lockFor : 120 , waitFor : 5 );
限制并发数:funnel()
Cache :: funnel ( 'foo' )
-> limit ( 3 )
-> releaseAfter ( 60 )
-> block ( 10 )
-> then ( function () {
// 成功获得配额
}, function () {
// 未获得
});
跨进程移交锁
$lock = Cache :: lock ( 'processing' , 120 );
if ( $lock -> get ()) {
ProcessPodcast :: dispatch ( $podcast , $lock -> owner ());
}
// 在任务里释放
Cache :: restoreLock ( 'processing' , $this -> owner ) -> release ();
强制释放:
Cache :: lock ( 'processing' ) -> forceRelease ();
刷新锁
延长当前锁的 TTL:
$lock = Cache :: lock ( 'generate-reports' , 60 );
if ( $lock -> get ()) {
foreach ( $reports as $report ) {
$report -> generate ();
$lock -> refresh ();
}
$lock -> release ();
}
缓存辅助函数
cache() 提供更简洁的写法:
$value = cache ( 'key' );
cache ([ 'key' => 'value' ], $seconds );
cache ([ 'key' => 'value' ], now () -> addMinutes ( 10 ));
cache () -> remember ( 'users' , $seconds , function () {
return DB :: table ( 'users' ) -> get ();
});
实践示例
缓存数据库查询
在控制器中缓存
use Illuminate\Support\Facades\ Cache ;
use Illuminate\Support\Facades\ DB ;
public function index () : array
{
$users = Cache :: remember ( 'all-users' , 3600 , function () {
return DB :: table ( 'users' ) -> orderBy ( 'name' ) -> get ();
});
return compact ( 'users' );
}
数据更新时清除
public function store ( Request $request ) : RedirectResponse
{
User :: create ( $request -> validated ());
Cache :: forget ( 'all-users' );
return redirect () -> route ( 'users.index' );
}
缓存 Eloquent 模型
use App\Models\ Product ;
use Illuminate\Support\Facades\ Cache ;
public function byCategory ( int $categoryId ) : array
{
$products = Cache :: remember (
"products:category:{ $categoryId }" ,
3600 ,
fn () => Product :: where ( 'category_id' , $categoryId )
-> where ( 'is_active' , true )
-> orderBy ( 'name' )
-> get ()
);
return compact ( 'products' );
}
缓存 API 响应
use Illuminate\Support\Facades\ Cache ;
use Illuminate\Support\Facades\ Http ;
public function getWeather ( string $city ) : array
{
return Cache :: remember (
"weather:{ $city }" ,
1800 ,
function () use ( $city ) {
$response = Http :: get ( 'https://api.weather.example.com/current' , [
'city' => $city ,
]);
return $response -> json ();
}
);
}
使用标签分组
use Illuminate\Support\Facades\ Cache ;
class ArticleController extends Controller
{
public function show ( Article $article ) : array
{
$data = Cache :: tags ([ 'articles' , "article:{ $article -> id }" ])
-> remember ( "article:{ $article -> id }:detail" , 3600 , function () use ( $article ) {
return $article -> load ([ 'author' , 'tags' , 'comments' ]);
});
return compact ( 'data' );
}
public function update ( Request $request , Article $article ) : RedirectResponse
{
$article -> update ( $request -> validated ());
Cache :: tags ([ "article:{ $article -> id }" ]) -> flush ();
return redirect () -> route ( 'articles.show' , $article );
}
}
开发 / 小型 :file 或 database
生产 / 高流量 :redis(可搭配 Laravel Horizon 监控)
AWS 环境 :dynamodb 或复用 S3 的 storage
测试 :array 或 null