缓存可用于通过在更快的或更靠近的存储系统中维护所需数据的第二个副本,使从昂贵或缓慢的资源读取速度更快。 例如,您可以将昂贵查询的结果存储在缓存中,或将不常更改的远程 Web 服务访问存储在缓存中。 一旦进入缓存,从缓存读取数据比访问远程资源要便宜得多。
CakePHP 中的缓存由 Cache
类提供。 此类提供了一个静态接口和统一的 API 来与各种缓存实现进行交互。 CakePHP 提供了多个缓存引擎,如果您需要构建自己的后端,它也提供了一个简单的接口。 内置的缓存引擎是
File
文件缓存是一个简单的缓存,它使用本地文件。 它是速度最慢的缓存引擎,并且没有为原子操作提供太多功能。 但是,由于磁盘存储通常很便宜,因此将大型对象或不常写入的元素存储在文件中效果很好。
Memcached
使用 Memcached 扩展。
Redis
使用 phpredis 扩展。 Redis 提供了一个类似于 Memcached 的快速且持久化的缓存系统,还提供了原子操作。
Apcu
APCu 缓存使用 PHP APCu 扩展。 此扩展在 Web 服务器上使用共享内存来存储对象。 这使得它非常快,并且能够提供原子读/写功能。
Array
将所有数据存储在数组中。 此引擎不提供持久存储,旨在用于应用程序测试套件。
Null
空引擎实际上不存储任何内容,并且所有读取操作都会失败。
无论您选择使用哪种 CacheEngine,您的应用程序都与 Cake\Cache\Cache
进行交互。
您的应用程序可以在其引导过程中配置任意数量的“引擎”。 缓存引擎配置在 config/app.php 中定义。
为了获得最佳性能,CakePHP 需要定义两个缓存引擎。
_cake_core_
用于存储文件映射以及 国际化 & 本地化 文件的解析结果。
_cake_model_
用于存储应用程序模型的模式描述。
使用多个引擎配置还可以让您根据需要逐步更改存储。 例如,在您的 config/app.php 中,您可以添加以下内容
// ...
'Cache' => [
'short' => [
'className' => 'File',
'duration' => '+1 hours',
'path' => CACHE,
'prefix' => 'cake_short_',
],
// Using a fully namespaced name.
'long' => [
'className' => 'Cake\Cache\Engine\FileEngine',
'duration' => '+1 week',
'probability' => 100,
'path' => CACHE . 'long' . DS,
],
]
// ...
配置选项也可以作为 DSN 字符串提供。 这在使用环境变量或 PaaS 提供商时很有用
Cache::setConfig('short', [
'url' => 'memcached://user:password@cache-host/?timeout=3600&prefix=myapp_',
]);
使用 DSN 字符串时,您可以将任何其他参数/选项定义为查询字符串参数。
您也可以在运行时配置缓存引擎
// Using a short name
Cache::setConfig('short', [
'className' => 'File',
'duration' => '+1 hours',
'path' => CACHE,
'prefix' => 'cake_short_'
]);
// Using a fully namespaced name.
Cache::setConfig('long', [
'className' => 'Cake\Cache\Engine\FileEngine',
'duration' => '+1 week',
'probability' => 100,
'path' => CACHE . 'long' . DS,
]);
// Using a constructed object.
$object = new FileEngine($config);
Cache::setConfig('other', $object);
这些引擎配置的名称(“short” 和 “long”)用作 Cake\Cache\Cache::write()
和 Cake\Cache\Cache::read()
的 $config
参数。 配置缓存引擎时,您可以使用以下语法引用类名
// Short name (in App\ or Cake namespaces)
Cache::setConfig('long', ['className' => 'File']);
// Plugin short name
Cache::setConfig('long', ['className' => 'MyPlugin.SuperCache']);
// Full namespace
Cache::setConfig('long', ['className' => 'Cake\Cache\Engine\FileEngine']);
// An object implementing CacheEngineInterface
Cache::setConfig('long', ['className' => $myCache]);
注意
使用 FileEngine 时,您可能需要使用 mask
选项来确保缓存文件具有正确的权限。
每个引擎都接受以下选项
duration
指定此缓存配置中的项目持续时间。 指定为与 strtotime()
兼容的表达式。
groups
与存储在此配置中的每个键关联的组或“标签”列表。 当您需要从缓存中删除数据子集时很有用。
prefix
前缀添加到所有条目。 当您需要与其他缓存配置或其他应用程序共享键空间时很有用。
probability
命中缓存 gc 清理的概率。 设置为 0 将禁用 Cache::gc()
从不被自动调用。
FileEngine 使用以下引擎特定选项
isWindows
自动填充主机是 Windows 还是非 Windows。
lock
文件写入之前是否应锁定?
mask
用于创建文件的掩码
path
缓存文件应保存到的路径。 默认为系统的临时目录。
RedisEngine 使用以下引擎特定选项
port
您的 Redis 服务器运行的端口。
host
您的 Redis 服务器运行的主机。
database
用于连接的数据库编号。
password
Redis 服务器密码。
persistent
是否应建立到 Redis 的持久连接。
timeout
Redis 的连接超时。
unix_socket
Redis 的 Unix 套接字的路径。
tls
通过 TLS 连接到 Redis。
ssl_key
用于 TLS 连接的 ssl 私钥。
ssl_ca
用于 TLS 连接的 ssl 证书颁发机构文件。
ssl_cert
用于 TLS 连接的 ssl 证书。
添加到版本 5.1.0: TLS 连接在 5.1 中添加。
compress
是否压缩数据。
username
登录以访问 Memcache 服务器。
password
访问 Memcache 服务器的密码。
persistent
持久连接的名称。所有使用相同持久值配置的配置将共享一个底层连接。
serialize
用于序列化数据的序列化引擎。可用的引擎是 php、igbinary 和 json。除了 php 之外,memcached 扩展必须与相应的序列化支持一起编译。
servers
Memcached 服务器的字符串或数组。如果是一个数组,MemcacheEngine 将使用它们作为池。
duration
请注意,任何超过 30 天的持续时间将被视为真实的 Unix 时间值,而不是相对于当前时间的偏移量。
options
Memcached 客户端的附加选项。应该是一个选项 => 值的数组。使用 \Memcached::OPT_*
常量作为键。
如果引擎不可用,例如 FileEngine
尝试写入不可写文件夹或 RedisEngine
无法连接到 Redis,引擎将回退到无操作 NullEngine
并触发可记录的错误。这可以防止应用程序因缓存失败而抛出未捕获的异常。
您可以使用 fallback
配置键配置缓存配置以回退到指定的配置。
Cache::setConfig('redis', [
'className' => 'Redis',
'duration' => '+1 hours',
'prefix' => 'cake_redis_',
'host' => '127.0.0.1',
'port' => 6379,
'fallback' => 'default',
]);
如果初始化 RedisEngine
实例失败,redis
缓存配置将回退到使用 default
缓存配置。如果初始化 default
缓存配置的引擎也失败,在这种情况下,引擎将再次回退到 NullEngine
并防止应用程序抛出未捕获的异常。
您可以使用 false
关闭缓存回退。
Cache::setConfig('redis', [
'className' => 'Redis',
'duration' => '+1 hours',
'prefix' => 'cake_redis_',
'host' => '127.0.0.1',
'port' => 6379,
'fallback' => false
]);
如果没有回退缓存,缓存失败将作为异常引发。
创建配置后,您无法更改它。相反,您应该使用 Cake\Cache\Cache::drop()
和 Cake\Cache\Cache::setConfig()
删除配置并重新创建它。删除缓存引擎将删除配置并销毁适配器(如果它已构建)。
Cache::write()
将 $value 写入缓存。您可以稍后通过引用 $key
来读取或删除此值。您也可以指定一个可选配置来存储缓存。如果没有指定 $config
,将使用默认配置。 Cache::write()
可以存储任何类型的对象,非常适合存储模型查找的结果。
$posts = Cache::read('posts');
if ($posts === null) {
$posts = $someService->getAllPosts();
Cache::write('posts', $posts);
}
使用 Cache::write()
和 Cache::read()
减少访问数据库以获取帖子的次数。
注意
如果您计划缓存使用 CakePHP ORM 进行的查询的结果,最好使用查询对象的内置缓存功能,如 缓存已加载的结果 部分所述。
您可能会发现自己需要一次写入多个缓存键。虽然您可以使用对 write()
的多次调用,但 writeMany()
允许 CakePHP 在可用时使用更有效的存储 API。例如,使用 writeMany()
在使用 Memcached 时可以节省多个网络连接。
$result = Cache::writeMany([
'article-' . $slug => $article,
'article-' . $slug . '-comments' => $comments
]);
// $result will contain
['article-first-post' => true, 'article-first-post-comments' => true]
使用 Cache::add()
允许您在键在缓存中不存在的情况下原子地将键设置为值。如果键已存在于缓存后端或写入失败,add()
将返回 false
。
// Set a key to act as a lock
$result = Cache::add($lockKey, true);
if (!$result) {
return;
}
// Do an action where there can only be one process active at a time.
// Remove the lock key.
Cache::delete($lockKey);
警告
基于文件的缓存不支持原子写入。
缓存有助于读取通过缓存。如果命名缓存键存在,它将被返回。如果键不存在,将调用可调用对象,并将结果存储在提供的键的缓存中。
例如,您通常希望缓存远程服务调用结果。您可以使用 remember()
来简化此过程。
class IssueService
{
public function allIssues($repo)
{
return Cache::remember($repo . '-issues', function () use ($repo) {
return $this->fetchAll($repo);
});
}
}
Cache::read()
用于从 $config
中读取存储在 $key
下的缓存值。如果 $config
为 null,将使用默认配置。 Cache::read()
将返回缓存值(如果它是有效的缓存)或 null
(如果缓存已过期或不存在)。使用严格的比较运算符 ===
或 !==
来检查 Cache::read()
操作的成功与否。
例如
$cloud = Cache::read('cloud');
if ($cloud !== null) {
return $cloud;
}
// Generate cloud data
// ...
// Store data in cache
Cache::write('cloud', $cloud);
return $cloud;
或者,如果您使用另一个名为 short
的缓存配置,您可以像下面这样在 Cache::read()
和 Cache::write()
调用中指定它。
// Read key "cloud", but from short configuration instead of default
$cloud = Cache::read('cloud', 'short');
if ($cloud === null) {
// Generate cloud data
// ...
// Store data in cache, using short cache configuration instead of default
Cache::write('cloud', $cloud, 'short');
}
return $cloud;
在一次写入多个键后,您可能也希望读取它们。虽然您可以使用对 read()
的多次调用,但 readMany()
允许 CakePHP 在可用时使用更有效的存储 API。例如,使用 readMany()
在使用 Memcached 时可以节省多个网络连接。
$result = Cache::readMany([
'article-' . $slug,
'article-' . $slug . '-comments'
]);
// $result will contain
['article-first-post' => '...', 'article-first-post-comments' => '...']
Cache::delete()
用于从存储中完全删除缓存对象。
// Remove a key
Cache::delete('my_key');
从 4.4.0 版本开始,RedisEngine
还提供了一个 deleteAsync()
方法,该方法使用 UNLINK
操作删除缓存键。
Cache::pool('redis')->deleteAsync('my_key');
在一次写入多个键后,您可能想要删除它们。虽然您可以使用多次调用 delete()
,但 deleteMany()
允许 CakePHP 在可用时使用更高效的存储 API。例如,使用 deleteMany()
在使用 Memcached 时可以节省多个网络连接。
$result = Cache::deleteMany([
'article-' . $slug,
'article-' . $slug . '-comments'
]);
// $result will contain
['article-first-post' => true, 'article-first-post-comments' => true]
销毁缓存配置的所有缓存值。在像 Apcu、Memcached 这样的引擎中,缓存配置的前缀用于删除缓存条目。请确保不同的缓存配置具有不同的前缀。
// Will clear all keys.
Cache::clear();
从 4.4.0 版本开始,RedisEngine
还提供了一个 clearBlocking()
方法,该方法使用 UNLINK
操作删除缓存键。
Cache::pool('redis')->clearBlocking();
注意
由于 APCu 对 webserver 和 CLI 使用隔离的缓存,因此必须分别清除它们(CLI 无法清除 webserver,反之亦然)。
应用程序中的计数器是存储在缓存中的好选择。例如,一个简单的比赛剩余“名额”倒计时可以存储在缓存中。Cache 类公开了原子方式来增加/减少计数器值。对于这些值,原子操作非常重要,因为它可以减少竞争风险,以及两个用户同时将值减少一个,从而导致不正确的值。
在设置整数后,可以使用 increment()
和 decrement()
对其进行操作。
Cache::write('initial_count', 10);
// Later on
Cache::decrement('initial_count');
// Or
Cache::increment('initial_count');
注意
增加和减少不适用于 FileEngine。您应该使用 APCu、Redis 或 Memcached 代替。
您可以通过将不常改变的结果或频繁读取的结果放入缓存中来极大地提高应用程序的性能。一个完美的例子是 Cake\ORM\Table::find()
的结果。Query 对象允许您使用 cache()
方法缓存结果。有关更多信息,请参阅 Caching Loaded Results 部分。
有时您希望将多个缓存条目标记为属于某个组或命名空间。这对于在某些信息发生变化时批量失效键是一个常见的要求,这些信息在同一组中的所有条目之间共享。这可以通过在缓存配置中声明组来实现。
Cache::setConfig('site_home', [
'className' => 'Redis',
'duration' => '+999 days',
'groups' => ['comment', 'article'],
]);
假设您想要将首页生成的 HTML 存储在缓存中,但也希望在每次向数据库添加评论或帖子时自动失效此缓存。通过添加组 comment
和 article
,我们实际上用这两个组名标记了存储到此缓存配置中的任何键。
例如,每当添加新帖子时,我们都可以告诉 Cache 引擎删除与 article
组关联的所有条目。
// src/Model/Table/ArticlesTable.php
public function afterSave($event, $entity, $options = [])
{
if ($entity->isNew()) {
Cache::clearGroup('article', 'site_home');
}
}
groupConfigs()
可用于检索组和配置之间的映射,即:具有相同的组。
// src/Model/Table/ArticlesTable.php
/**
* A variation of previous example that clears all Cache configurations
* having the same group
*/
public function afterSave($event, $entity, $options = [])
{
if ($entity->isNew()) {
$configs = Cache::groupConfigs('article');
foreach ($configs['article'] as $config) {
Cache::clearGroup('article', $config);
}
}
}
组在所有使用相同引擎和相同前缀的缓存配置之间共享。如果您使用组并希望利用组删除,请为所有配置选择一个通用前缀。
在尝试找出与缓存过期相关的问题时,您可能需要禁用所有缓存读写。您可以使用 enable()
和 disable()
来实现。
// Disable all cache reads, and cache writes.
Cache::disable();
禁用后,所有读写都将返回 null
。
禁用后,可以使用 enable()
重新启用缓存。
// Re-enable all cache reads, and cache writes.
Cache::enable();
如果您需要检查缓存的状态,可以使用 enabled()
。
您可以在 App\Cache\Engine
中以及在插件中使用 $plugin\Cache\Engine
提供自定义的 Cache
引擎。缓存引擎必须位于缓存目录中。如果您有一个名为 MyCustomCacheEngine
的缓存引擎,它将被放置在 src/Cache/Engine/MyCustomCacheEngine.php 中。或者作为插件的一部分,放在 plugins/MyPlugin/src/Cache/Engine/MyCustomCacheEngine.php 中。来自插件的缓存配置需要使用插件点语法。
Cache::setConfig('custom', [
'className' => 'MyPlugin.MyCustomCache',
// ...
]);
自定义缓存引擎必须扩展 Cake\Cache\CacheEngine
,它定义了一些抽象方法,并提供了一些初始化方法。
CacheEngine 的必需 API 是
所有与 Cache 一起使用的缓存引擎的基类。
布尔值,表示成功。
将键的值写入缓存,如果数据成功缓存,则返回 true
,如果失败,则返回 false
。
缓存的值,如果失败则返回 null
。
从缓存中读取键。返回 null
表示条目已过期或不存在。
布尔值 true
表示成功。
从缓存中删除键。返回 false
表示条目不存在或无法删除。
布尔值 true
表示成功。
删除缓存中的所有键。如果 $check 为 true
,则应验证每个值是否确实已过期。
布尔值 true
表示成功。
删除缓存中属于同一组的所有键。
布尔值 true
表示成功。
递减键值下的数字并返回递减后的值
布尔值 true
表示成功。
递增键值下的数字并返回递增后的值