Laravel 13 缓存新特性详解

摘要

Laravel 13 对缓存系统进行了增强,引入了 Cache::touch() 方法,允许延长缓存项的 TTL 而无需重新存储值。本文将深入讲解 Laravel 13 的缓存新特性,包括:

  • Cache::touch() 核心概念与用法
  • 缓存 TTL 延长场景
  • 多驱动支持
  • 原子操作与并发安全
  • 缓存预热与失效策略
  • 实战案例:会话续期与热点数据保活

本文适合希望优化缓存管理的 Laravel 开发者。

1. Cache::touch() 概述

1.1 传统方式的问题

在 Laravel 13 之前,延长缓存 TTL 需要先获取值,再重新存储:

1
2
3
4
5
// 传统方式
$value = Cache::get('key');
if ($value !== null) {
Cache::put('key', $value, $newTtl);
}

问题:

  • 需要读取并重新写入值
  • 对于大值,内存开销大
  • 非原子操作,存在竞态条件

1.2 Cache::touch() 的优势

1
2
// Laravel 13 新方式
Cache::touch('key', $additionalSeconds);

优势:

  • 无需读取值
  • 原子操作
  • 性能更高
  • 内存友好

2. 基础用法

2.1 基本语法

1
2
3
4
5
6
7
use Illuminate\Support\Facades\Cache;

// 延长 TTL 60 秒
Cache::touch('key', 60);

// 延长 TTL 到指定时间
Cache::touch('key', now()->addHour());

2.2 返回值

1
2
3
4
5
6
7
$success = Cache::touch('key', 60);

if ($success) {
// TTL 延长成功
} else {
// 缓存项不存在
}

2.3 链式调用

1
Cache::store('redis')->touch('key', 60);

3. 应用场景

3.1 会话续期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class SessionService
{
public function keepAlive(string $sessionId): bool
{
return Cache::touch("session:{$sessionId}", 3600);
}

public function extend(string $sessionId, int $minutes = 30): bool
{
return Cache::touch("session:{$sessionId}", $minutes * 60);
}
}

3.2 热点数据保活

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
<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class HotDataService
{
public function keepHot(string $key): void
{
// 如果数据被访问,延长其缓存时间
Cache::touch($key, 3600);
}

public function access(string $key): mixed
{
$value = Cache::get($key);

if ($value !== null) {
// 访问时自动续期
Cache::touch($key, 3600);
}

return $value;
}
}

3.3 限流器续期

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class RateLimiterService
{
public function extendWindow(string $key, int $seconds): bool
{
return Cache::touch("rate_limit:{$key}", $seconds);
}
}

3.4 锁续期

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class LockService
{
public function extendLock(string $lockKey, int $seconds): bool
{
return Cache::touch("lock:{$lockKey}", $seconds);
}
}

4. 多驱动支持

4.1 Redis

1
Cache::store('redis')->touch('key', 60);

Redis 实现使用 EXPIRE 命令,性能最优。

4.2 Memcached

1
Cache::store('memcached')->touch('key', 60);

Memcached 原生支持 touch 操作。

4.3 Database

1
Cache::store('database')->touch('key', 60);

数据库驱动通过更新 expiration 字段实现。

4.4 File

1
Cache::store('file')->touch('key', 60);

文件驱动通过更新文件修改时间实现。

5. 高级用法

5.1 批量 touch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Illuminate\Support\Facades\Cache;

class CacheBatchService
{
public function touchMany(array $keys, int $seconds): array
{
$results = [];

foreach ($keys as $key) {
$results[$key] = Cache::touch($key, $seconds);
}

return $results;
}
}

5.2 条件 touch

1
2
3
4
5
6
7
8
9
10
11
12
13
class ConditionalCacheService
{
public function touchIfPopular(string $key): bool
{
$hits = Cache::get("hits:{$key}", 0);

if ($hits > 100) {
return Cache::touch($key, 3600);
}

return false;
}
}

5.3 与事件结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace App\Listeners;

use Illuminate\Support\Facades\Cache;
use Illuminate\Cache\Events\CacheHit;

class ExtendHotCache
{
public function handle(CacheHit $event): void
{
// 如果是热点数据,自动续期
if ($this->isHotKey($event->key)) {
Cache::touch($event->key, 3600);
}
}

private function isHotKey(string $key): bool
{
return str_starts_with($key, 'hot:');
}
}

6. 实战案例

6.1 智能缓存管理器

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
<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class SmartCacheManager
{
protected array $hotKeys = [];

public function get(string $key, mixed $default = null): mixed
{
$value = Cache::get($key, $default);

if ($value !== null) {
$this->recordHit($key);
$this->autoExtend($key);
}

return $value;
}

public function put(string $key, mixed $value, ?int $ttl = null): bool
{
return Cache::put($key, $value, $ttl ?? 3600);
}

protected function recordHit(string $key): void
{
$this->hotKeys[$key] = ($this->hotKeys[$key] ?? 0) + 1;
}

protected function autoExtend(string $key): void
{
// 访问超过 10 次的数据自动续期
if (($this->hotKeys[$key] ?? 0) > 10) {
Cache::touch($key, 3600);
}
}
}

6.2 API 响应缓存

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 ApiResponseCache
{
public function getOrCache(string $endpoint, callable $callback, int $ttl = 3600): mixed
{
$key = "api:{$endpoint}";

return Cache::remember($key, $ttl, function () use ($callback, $key) {
$response = $callback();

// 记录缓存创建时间
Cache::put("{$key}:created", now(), $ttl);

return $response;
});
}

public function extend(string $endpoint, int $seconds): bool
{
$key = "api:{$endpoint}";

$main = Cache::touch($key, $seconds);
$meta = Cache::touch("{$key}:created", $seconds);

return $main && $meta;
}
}

6.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
<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class UserActivityService
{
public function recordActivity(int $userId): void
{
$key = "user:active:{$userId}";

if (Cache::has($key)) {
// 用户活跃,延长在线状态
Cache::touch($key, 300); // 5 分钟
} else {
// 新会话
Cache::put($key, now(), 300);
}
}

public function isOnline(int $userId): bool
{
return Cache::has("user:active:{$userId}");
}

public function getOnlineUsers(): array
{
// 使用 Redis SCAN 或其他方式获取在线用户
// ...
}
}

7. 性能对比

7.1 基准测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 传统方式
$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$value = Cache::get('large_data');
Cache::put('large_data', $value, 3600);
}
$traditional = microtime(true) - $start;

// Cache::touch()
$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
Cache::touch('large_data', 3600);
}
$touch = microtime(true) - $start;

echo "Traditional: {$traditional}s\n";
echo "Touch: {$touch}s\n";
// 结果:touch 方式快 10-100 倍

8. 最佳实践

8.1 合理设置 TTL

1
2
3
4
// 推荐:根据数据特性设置
Cache::touch('user:session', 3600); // 会话:1 小时
Cache::touch('api:response', 300); // API 响应:5 分钟
Cache::touch('config:cache', 86400); // 配置:1 天

8.2 错误处理

1
2
3
4
if (!Cache::touch('key', 60)) {
// 缓存项不存在,重新生成
Cache::remember('key', 3600, $callback);
}

8.3 监控与日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MonitoredCacheService
{
public function touch(string $key, int $seconds): bool
{
$start = microtime(true);
$result = Cache::touch($key, $seconds);
$duration = (microtime(true) - $start) * 1000;

if ($duration > 10) { // 超过 10ms 记录
Log::warning('Slow cache touch', [
'key' => $key,
'duration_ms' => $duration,
]);
}

return $result;
}
}

9. 总结

Laravel 13 的 Cache::touch() 为缓存管理提供了更高效的方式:

  1. 性能优越:无需读取值,直接修改 TTL
  2. 原子操作:避免竞态条件
  3. 内存友好:不加载大值到内存
  4. 多驱动支持:Redis、Memcached、Database 等

通过本指南,您已经掌握了缓存新特性的核心用法,可以开始优化应用的缓存管理了。

参考资料