跳到内容

缓存池和受支持的适配器

编辑此页

缓存池是缓存项的逻辑仓库。它们执行对项的所有常见操作,例如保存或查找它们。缓存池独立于实际的缓存实现。因此,即使底层缓存机制从基于文件系统的缓存更改为基于 Redis 或数据库的缓存,应用程序也可以继续使用相同的缓存池。

使用缓存契约

CacheInterface 允许仅使用两个方法和一个回调来获取、存储和删除缓存项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Contracts\Cache\ItemInterface;

$cache = new FilesystemAdapter();

// The callable will only be executed on a cache miss.
$value = $cache->get('my_cache_key', function (ItemInterface $item): string {
    $item->expiresAfter(3600);

    // ... do some HTTP request or heavy computations
    $computedValue = 'foobar';

    return $computedValue;
});

echo $value; // 'foobar'

// ... and to remove the cache key
$cache->delete('my_cache_key');

开箱即用,使用此接口通过锁定和提前过期提供印章跳跃保护。提前过期可以通过 get() 方法的第三个 "beta" 参数来控制。有关更多信息,请参阅 缓存组件 文章。

提前过期可以在回调内部通过调用 isHit() 方法来检测:如果它返回 true,则表示我们当前正在其过期日期之前重新计算一个值。

对于高级用例,回调可以接受第二个通过引用传递的 bool &$save 参数。通过在回调内部将 $save 设置为 false,您可以指示缓存池,返回的值不应该存储在后端。

使用 PSR-6

查找缓存项

缓存池定义了三种查找缓存项的方法。最常用的方法是 getItem($key),它返回由给定键标识的缓存项

1
2
3
4
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache');
$latestNews = $cache->getItem('latest_news');

如果给定的键没有定义项,则该方法不会返回 null 值,而是返回一个实现了 CacheItem 类的空对象。

如果您需要同时获取多个缓存项,请改用 getItems([$key1, $key2, ...]) 方法

1
2
// ...
$stocks = $cache->getItems(['AAPL', 'FB', 'GOOGL', 'MSFT']);

同样,如果任何键不代表有效的缓存项,您将不会得到 null 值,而是得到一个空的 CacheItem 对象。

与获取缓存项相关的最后一个方法是 hasItem($key),如果存在由给定键标识的缓存项,则返回 true

1
2
// ...
$hasBadges = $cache->hasItem('user_'.$userId.'_badges');

保存缓存项

保存缓存项最常用的方法是 Psr\Cache\CacheItemPoolInterface::save,它立即将项存储在缓存中(如果项已保存,则返回 true;如果发生某些错误,则返回 false

1
2
3
4
// ...
$userFriends = $cache->getItem('user_'.$userId.'_friends');
$userFriends->set($user->getFriends());
$isSaved = $cache->save($userFriends);

有时您可能希望不立即保存对象,以提高应用程序性能。在这些情况下,使用 Psr\Cache\CacheItemPoolInterface::saveDeferred 方法将缓存项标记为“准备持久化”,然后在您准备好持久化所有缓存项时调用 Psr\Cache\CacheItemPoolInterface::commit 方法

1
2
3
4
5
6
7
8
// ...
$isQueued = $cache->saveDeferred($userFriends);
// ...
$isQueued = $cache->saveDeferred($userPreferences);
// ...
$isQueued = $cache->saveDeferred($userRecentProducts);
// ...
$isSaved = $cache->commit();

当缓存项已成功添加到“持久化队列”时,saveDeferred() 方法返回 true,否则返回 falsecommit() 方法在所有待处理项都成功保存时返回 true,否则返回 false

移除缓存项

缓存池包含删除缓存项、部分缓存项或所有缓存项的方法。最常用的是 Psr\Cache\CacheItemPoolInterface::deleteItem,它删除由给定键标识的缓存项(当项已成功删除或不存在时返回 true,否则返回 false

1
2
// ...
$isDeleted = $cache->deleteItem('user_'.$userId);

使用 Psr\Cache\CacheItemPoolInterface::deleteItems 方法同时删除多个缓存项(仅当所有项都已删除时才返回 true,即使任何或某些项不存在)

1
2
// ...
$areDeleted = $cache->deleteItems(['category1', 'category2']);

最后,要删除池中存储的所有缓存项,请使用 Psr\Cache\CacheItemPoolInterface::clear 方法(当所有项都成功删除时,它返回 true

1
2
// ...
$cacheIsEmpty = $cache->clear();

提示

如果在 Symfony 应用程序内部使用缓存组件,您可以使用以下命令从缓存池中删除项(这些命令位于 framework bundle 中)

给定池中删除一个特定项

1
2
3
4
$ php bin/console cache:pool:delete <cache-pool-name> <cache-key-name>

# deletes the "cache_key" item from the "cache.app" pool
$ php bin/console cache:pool:delete cache.app cache_key

您还可以从给定池中删除所有项

1
2
3
4
5
6
7
$ php bin/console cache:pool:clear <cache-pool-name>

# clears the "cache.app" pool
$ php bin/console cache:pool:clear cache.app

# clears the "cache.validation" and "cache.app" pool
$ php bin/console cache:pool:clear cache.validation cache.app

清理缓存项

某些缓存池不包含用于清理过期缓存项的自动化机制。例如,FilesystemAdapter 缓存不会删除过期的缓存项,直到显式请求某个项并确定其已过期,例如,通过调用 Psr\Cache\CacheItemPoolInterface::getItem。在某些工作负载下,这可能会导致过时的缓存条目持续存在,远远超过其过期时间,从而导致过多的过期缓存项浪费大量的磁盘或内存空间。

此缺点已通过引入 PruneableInterface 解决,它定义了抽象方法 prune()ChainAdapterDoctrineDbalAdapterFilesystemAdapterPdoAdapterPhpFilesAdapter 都实现了这个新接口,允许手动删除过时的缓存项

1
2
3
4
5
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache');
// ... do some set and get operations
$cache->prune();

ChainAdapter 实现本身不直接包含任何清理逻辑。相反,当调用链式适配器的 prune() 方法时,调用将委托给其所有兼容的缓存适配器(而那些未实现 PruneableInterface 的适配器将被静默忽略)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\PdoAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;

$cache = new ChainAdapter([
    new ApcuAdapter(),       // does NOT implement PruneableInterface
    new FilesystemAdapter(), // DOES implement PruneableInterface
    new PdoAdapter(),        // DOES implement PruneableInterface
    new PhpFilesAdapter(),   // DOES implement PruneableInterface
    // ...
]);

// prune will proxy the call to PdoAdapter, FilesystemAdapter and PhpFilesAdapter,
// while silently skipping ApcuAdapter
$cache->prune();

提示

如果在 Symfony 应用程序内部使用缓存组件,您可以使用以下命令从所有池中清理所有项(这些命令位于 framework bundle 中)

1
$ php bin/console cache:pool:prune
此作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本