Laravel 13 缓存高级特性深度解析
缓存是提高应用程序性能的关键技术。本文将深入探讨 Laravel 13 中缓存的高级特性。
缓存基础回顾
基本操作
1 2 3 4 5 6 7 8 9
| <?php
use Illuminate\Support\Facades\Cache;
Cache::put('key', 'value', $seconds); Cache::get('key', 'default'); Cache::has('key'); Cache::forget('key'); Cache::flush();
|
原子锁
基本锁操作
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('processing', 10);
if ($lock->get()) { try { $this->process(); } finally { $lock->release(); } }
|
锁等待
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('processing', 10);
if ($lock->block(5)) { try { $this->process(); } finally { $lock->release(); } }
|
自动释放
1 2 3 4 5 6 7 8 9 10 11
| <?php
use Illuminate\Support\Facades\Cache;
Cache::lock('processing', 10)->get(function () { $this->process(); });
Cache::lock('processing', 10)->block(5, function () { $this->process(); });
|
跨进程锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('processing', 10);
if ($lock->get()) { $lockOwner = $lock->owner();
Cache::put('lock:owner', $lockOwner, 10); }
$storedOwner = Cache::get('lock:owner');
if ($lock->isOwnedBy($storedOwner)) { $lock->release(); }
|
缓存标签
标签操作
1 2 3 4 5 6 7 8 9 10 11 12
| <?php
use Illuminate\Support\Facades\Cache;
Cache::tags(['people', 'artists'])->put('john', 'John Doe', 3600); Cache::tags(['people', 'authors'])->put('anne', 'Anne Smith', 3600);
$john = Cache::tags(['people', 'artists'])->get('john');
Cache::tags(['people', 'artists'])->flush();
Cache::tags(['people'])->flush();
|
标签缓存库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
class ArticleCacheService { protected string $tag = 'articles';
public function remember(int $id, callable $callback) { return Cache::tags([$this->tag])->remember( "article.{$id}", 3600, $callback ); }
public function forget(int $id): bool { return Cache::tags([$this->tag])->forget("article.{$id}"); }
public function flush(): void { Cache::tags([$this->tag])->flush(); } }
|
缓存助手函数
remember() 方法
1 2 3 4 5 6 7 8 9 10 11
| <?php
use Illuminate\Support\Facades\Cache;
$value = Cache::remember('users.active', 3600, function () { return User::where('active', true)->get(); });
$value = Cache::rememberForever('users.active', function () { return User::where('active', true)->get(); });
|
rememberForever() 方法
1 2 3 4 5 6 7 8 9 10 11
| <?php
use Illuminate\Support\Facades\Cache;
$config = Cache::rememberForever('app.config', function () { return [ 'site_name' => config('app.name'), 'version' => config('app.version'), 'features' => config('features'), ]; });
|
增减操作
增量操作
1 2 3 4 5 6 7 8 9
| <?php
use Illuminate\Support\Facades\Cache;
Cache::put('counter', 0); Cache::increment('counter'); Cache::increment('counter', 5); Cache::decrement('counter'); Cache::decrement('counter', 3);
|
原子计数器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
class RateLimiter { protected string $key; protected int $maxAttempts; protected int $decayMinutes;
public function __construct(string $key, int $maxAttempts = 60, int $decayMinutes = 1) { $this->key = $key; $this->maxAttempts = $maxAttempts; $this->decayMinutes = $decayMinutes; }
public function hit(): int { $key = "rate_limit:{$this->key}";
$added = Cache::add($key, 0, $this->decayMinutes * 60);
$hits = Cache::increment($key);
return $hits; }
public function tooManyAttempts(): bool { $key = "rate_limit:{$this->key}"; $hits = Cache::get($key, 0);
return $hits >= $this->maxAttempts; }
public function remaining(): int { $key = "rate_limit:{$this->key}"; $hits = Cache::get($key, 0);
return max(0, $this->maxAttempts - $hits); }
public function reset(): void { Cache::forget("rate_limit:{$this->key}"); } }
|
缓存存储
多存储支持
1 2 3 4 5 6 7
| <?php
use Illuminate\Support\Facades\Cache;
$value = Cache::store('redis')->get('key'); Cache::store('file')->put('key', 'value', 3600); Cache::store('database')->forever('key', 'value');
|
自定义存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| <?php
namespace App\Cache;
use Illuminate\Contracts\Cache\Store;
class CustomCacheStore implements Store { protected string $prefix;
public function __construct(string $prefix = '') { $this->prefix = $prefix; }
public function get($key): mixed { return $this->retrieve($this->prefix . $key); }
public function many(array $keys): array { $values = [];
foreach ($keys as $key) { $values[$key] = $this->get($key); }
return $values; }
public function put($key, $value, $seconds): bool { return $this->store($this->prefix . $key, $value, $seconds); }
public function putMany(array $values, $seconds): bool { foreach ($values as $key => $value) { $this->put($key, $value, $seconds); }
return true; }
public function increment($key, $value = 1): int|bool { return $this->incrementValue($this->prefix . $key, $value); }
public function decrement($key, $value = 1): int|bool { return $this->decrementValue($this->prefix . $key, $value); }
public function forever($key, $value): bool { return $this->store($this->prefix . $key, $value, 0); }
public function forget($key): bool { return $this->delete($this->prefix . $key); }
public function flush(): bool { return $this->clearAll(); }
public function getPrefix(): string { return $this->prefix; }
protected function retrieve(string $key): mixed { return null; }
protected function store(string $key, mixed $value, int $seconds): bool { return true; }
protected function delete(string $key): bool { return true; }
protected function clearAll(): bool { return true; }
protected function incrementValue(string $key, int $value): int|bool { return 0; }
protected function decrementValue(string $key, int $value): int|bool { return 0; } }
|
缓存事件
监听缓存事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Event; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; use Illuminate\Cache\Events\KeyForgotten; use Illuminate\Cache\Events\KeyWritten;
class CacheEventServiceProvider extends ServiceProvider { public function boot(): void { Event::listen(CacheHit::class, function ($event) { \Log::debug("Cache hit: {$event->key}"); });
Event::listen(CacheMissed::class, function ($event) { \Log::debug("Cache missed: {$event->key}"); });
Event::listen(KeyWritten::class, function ($event) { \Log::debug("Cache written: {$event->key}"); });
Event::listen(KeyForgotten::class, function ($event) { \Log::debug("Cache forgotten: {$event->key}"); }); } }
|
缓存装饰器
模型缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <?php
namespace App\Traits;
use Illuminate\Support\Facades\Cache;
trait Cacheable { protected function getCacheKey(string $key): string { return sprintf( '%s:%s:%s', $this->getTable(), $this->getKey(), $key ); }
protected function cacheRemember(string $key, int $ttl, callable $callback): mixed { return Cache::remember($this->getCacheKey($key), $ttl, $callback); }
protected function cacheForget(string $key): bool { return Cache::forget($this->getCacheKey($key)); }
protected function cacheFlush(): void { $pattern = $this->getTable() . ':' . $this->getKey() . ':*';
$keys = Cache::getStore()->getRedis()->keys($pattern);
foreach ($keys as $key) { Cache::forget($key); } } }
|
查询缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <?php
namespace App\Services;
use Illuminate\Support\Facades\Cache; use Illuminate\Database\Eloquent\Model;
class QueryCacheService { protected int $ttl = 3600; protected string $prefix = 'query:';
public function remember(Model $model, string $method, array $args, callable $callback): mixed { $key = $this->generateKey($model, $method, $args);
return Cache::remember($key, $this->ttl, $callback); }
public function forget(Model $model, string $method, array $args = []): bool { $key = $this->generateKey($model, $method, $args);
return Cache::forget($key); }
public function forgetModel(Model $model): void { $pattern = $this->prefix . get_class($model) . ':' . $model->getKey() . ':*';
$this->flushPattern($pattern); }
protected function generateKey(Model $model, string $method, array $args): string { return $this->prefix . get_class($model) . ':' . $model->getKey() . ':' . $method . ':' . md5(json_encode($args)); }
protected function flushPattern(string $pattern): void { $redis = Cache::getStore()->getRedis(); $keys = $redis->keys($pattern);
foreach ($keys as $key) { Cache::forget($key); } } }
|
缓存预热
预热命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <?php
namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Support\Facades\Cache; use App\Models\{User, Product, Category};
class WarmCache extends Command { protected $signature = 'cache:warm';
protected $description = 'Warm up application cache';
public function handle(): int { $this->info('Warming cache...');
$this->warmUsers(); $this->warmProducts(); $this->warmCategories();
$this->info('Cache warmed successfully!');
return 0; }
protected function warmUsers(): void { $this->info('Warming users cache...');
Cache::remember('users.active', 3600, function () { return User::where('active', true)->get(); });
Cache::remember('users.count', 3600, function () { return User::count(); }); }
protected function warmProducts(): void { $this->info('Warming products cache...');
Cache::remember('products.featured', 3600, function () { return Product::where('featured', true)->get(); });
Cache::remember('products.categories', 3600, function () { return Category::withCount('products')->get(); }); }
protected function warmCategories(): void { $this->info('Warming categories cache...');
Cache::remember('categories.all', 3600, function () { return Category::with('children')->whereNull('parent_id')->get(); }); } }
|
缓存失效策略
基于时间的失效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
class ConfigurationService { protected int $ttl = 3600;
public function get(string $key, mixed $default = null): mixed { return Cache::remember("config.{$key}", $this->ttl, function () use ($key, $default) { return \App\Models\Configuration::where('key', $key)->value('value') ?? $default; }); }
public function set(string $key, mixed $value): void { \App\Models\Configuration::updateOrCreate( ['key' => $key], ['value' => $value] );
Cache::forget("config.{$key}"); }
public function flush(): void { Cache::flush(); } }
|
基于事件的失效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php
namespace App\Observers;
use App\Models\Product; use Illuminate\Support\Facades\Cache;
class ProductObserver { public function created(Product $product): void { $this->clearProductCache($product); }
public function updated(Product $product): void { $this->clearProductCache($product); }
public function deleted(Product $product): void { $this->clearProductCache($product); }
protected function clearProductCache(Product $product): void { Cache::forget("product.{$product->id}"); Cache::forget('products.featured'); Cache::forget('products.latest');
Cache::tags(['products'])->flush(); } }
|
测试缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php
namespace Tests\Unit\Services;
use Tests\TestCase; use App\Services\ConfigurationService; use Illuminate\Support\Facades\Cache;
class CacheTest extends TestCase { public function test_cache_remember(): void { Cache::shouldReceive('remember') ->once() ->with('test.key', 3600, \Closure::class) ->andReturn('cached_value');
$service = new ConfigurationService(); $value = $service->get('test.key');
$this->assertEquals('cached_value', $value); }
public function test_cache_forget(): void { Cache::shouldReceive('forget') ->once() ->with('config.test_key');
$service = new ConfigurationService(); $service->set('test_key', 'new_value'); } }
|
最佳实践
1. 合理设置 TTL
1 2 3 4 5
| <?php
Cache::put('config', $config, 86400); Cache::put('user.session', $session, 3600); Cache::put('rate_limit', $count, 60);
|
2. 使用标签组织
1 2 3 4
| <?php
Cache::tags(['user:' . $userId])->put('profile', $profile, 3600); Cache::tags(['user:' . $userId])->flush();
|
3. 缓存穿透保护
1 2 3 4 5 6 7
| <?php
$value = Cache::remember('key', 3600, function () { $value = Model::find($id);
return $value ?? false; });
|
总结
Laravel 13 的缓存系统提供了丰富的功能来优化应用程序性能。通过合理使用原子锁、标签、事件等高级特性,可以构建高效、可靠的缓存策略。