缓存池和受支持的适配器
缓存池是缓存项的逻辑仓库。它们执行对项的所有常见操作,例如保存或查找它们。缓存池独立于实际的缓存实现。因此,即使底层缓存机制从基于文件系统的缓存更改为基于 Redis 或数据库的缓存,应用程序也可以继续使用相同的缓存池。
创建缓存池
缓存池通过缓存适配器创建,缓存适配器是实现了 CacheInterface 和 Psr\Cache\CacheItemPoolInterface
的类。此组件提供了几个适配器,可以在您的应用程序中直接使用。
使用缓存契约
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
,否则返回 false
。commit()
方法在所有待处理项都成功保存时返回 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()。ChainAdapter、DoctrineDbalAdapter 和 FilesystemAdapter、PdoAdapter 和 PhpFilesAdapter 都实现了这个新接口,允许手动删除过时的缓存项
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