5 关注者

数据缓存

数据缓存是指将一些 PHP 变量存储在缓存中,并在以后从缓存中检索它。它也是更高级缓存功能(例如 查询缓存页面缓存)的基础。

以下代码是数据缓存的典型用法模式,其中 $cache 指的是 缓存组件

// try retrieving $data from cache
$data = $cache->get($key);

if ($data === false) {
    // $data is not found in cache, calculate it from scratch
    $data = $this->calculateSomething();

    // store $data in cache so that it can be retrieved next time
    $cache->set($key, $data);
}

// $data is available here

从 2.0.11 版本开始,缓存组件 提供了 getOrSet() 方法,简化了获取、计算和存储数据的代码。以下代码与前面的示例完全相同

$data = $cache->getOrSet($key, function () {
    return $this->calculateSomething();
});

当缓存具有与 $key 关联的数据时,将返回缓存的值。否则,将执行传递的匿名函数来计算将被缓存并返回的值。

如果匿名函数需要来自外部作用域的一些数据,可以使用 use 语句传递它。例如

$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
    return $this->calculateSomething($user_id);
});

注意:getOrSet() 方法也支持持续时间和依赖项。请参阅 缓存过期缓存依赖 以了解更多信息。

缓存组件

数据缓存依赖于所谓的缓存组件,这些组件表示各种缓存存储,例如内存、文件、数据库。

缓存组件通常注册为 应用程序组件,以便可以全局配置和访问它们。以下代码展示了如何配置 cache 应用程序组件以使用 memcached 和两个缓存服务器

'components' => [
    'cache' => [
        'class' => 'yii\caching\MemCache',
        'servers' => [
            [
                'host' => 'server1',
                'port' => 11211,
                'weight' => 100,
            ],
            [
                'host' => 'server2',
                'port' => 11211,
                'weight' => 50,
            ],
        ],
    ],
],

然后,您可以使用表达式 Yii::$app->cache 访问上述缓存组件。

如果未指定缓存组件,则 Yii 将使用 yii\caching\FileCache 作为默认值。

因为所有缓存组件都支持同一组 API,所以您可以通过在应用程序配置中重新配置它来将底层缓存组件替换为不同的组件,而无需修改使用缓存的代码。例如,您可以修改上述配置以使用 APC 缓存

'components' => [
    'cache' => [
        'class' => 'yii\caching\ApcCache',
    ],
],

提示:您可以注册多个缓存应用程序组件。组件名为 cache,许多依赖缓存的类(例如 yii\web\UrlManager)默认使用它。

支持的缓存存储

Yii 支持广泛的缓存存储。以下是总结

  • yii\caching\ApcCache: 使用 PHP APC 扩展。在处理集中式厚应用程序(例如一台服务器、没有专用的负载均衡器等)的缓存时,可以将此选项视为最快的一个。
  • yii\caching\DbCache: 使用数据库表来存储缓存数据。要使用此缓存,必须创建一个表,如 yii\caching\DbCache::$cacheTable 中所述。

  • yii\caching\ArrayCache:仅为当前请求提供缓存,方法是将值存储在数组中。为了提高 ArrayCache 的性能,可以通过将 yii\caching\ArrayCache::$serializer 设置为 false 来禁用存储数据的序列化。
  • yii\caching\DummyCache:用作缓存占位符,不执行真正的缓存。此组件的目的是简化需要检查缓存可用性的代码。例如,在开发期间或服务器没有实际缓存支持的情况下,您可以将缓存组件配置为使用此缓存。启用实际缓存支持后,您可以切换为使用相应的缓存组件。在这两种情况下,您都可以使用相同的代码 Yii::$app->cache->get($key) 来尝试从缓存中检索数据,而无需担心 Yii::$app->cache 可能是 null
  • yii\caching\FileCache:使用标准文件来存储缓存数据。这特别适用于缓存大量数据,例如页面内容。
  • yii\caching\MemCache:使用 PHP memcachememcached 扩展。在处理分布式应用程序(例如,具有多个服务器、负载均衡器等)中的缓存时,此选项可以被视为最快的一种。
  • yii\redis\Cache:实现基于 Redis 键值存储的缓存组件(需要 redis 版本 2.6.12 或更高版本)。
  • yii\caching\WinCache:使用 PHP WinCache (另请参阅) 扩展。
  • yii\caching\XCache (已弃用):使用 PHP XCache 扩展。
  • yii\caching\ZendDataCache (已弃用):使用 Zend Data Cache 作为底层缓存媒介。

提示:您可以在同一个应用程序中使用不同的缓存存储。一种常见的策略是使用基于内存的缓存存储来存储数据量小但经常使用的数据(例如统计数据),并使用基于文件或数据库的缓存存储来存储数据量大且使用频率低的数据(例如页面内容)。

缓存 API

所有缓存组件都具有相同的基类 yii\caching\Cache,因此支持以下 API

  • get():使用指定的键从缓存中检索数据项。如果在缓存中找不到数据项或数据项已过期/失效,则将返回 false 值。
  • set():将由键标识的数据项存储在缓存中。
  • add():如果在缓存中找不到键,则将由键标识的数据项存储在缓存中。
  • getOrSet():使用指定的键从缓存中检索数据项,或执行传递的回调函数,并通过键将回调函数的返回值存储在缓存中,然后返回该数据。
  • multiGet():使用指定的键从缓存中检索多个数据项。
  • multiSet():将多个数据项存储在缓存中。每个项目都由一个键标识。
  • multiAdd():将多个数据项存储在缓存中。每个项目都由一个键标识。如果缓存中已存在键,则将跳过该数据项。
  • exists():返回一个值,指示指定的键是否在缓存中找到。
  • delete():从缓存中删除由键标识的数据项。
  • flush():从缓存中删除所有数据项。

注意:不要直接缓存 false 布尔值,因为 get() 方法使用 false 返回值来指示在缓存中找不到数据项。您可以将 false 放入数组中并缓存此数组以避免此问题。

某些缓存存储(例如 MemCache、APC)支持以批处理模式检索多个缓存值,这可能会减少检索缓存数据所涉及的开销。multiGet()multiAdd() API 用于利用此功能。如果底层缓存存储不支持此功能,则将对其进行模拟。

因为 yii\caching\Cache 实现 ArrayAccess,所以缓存组件可以用作数组。以下是一些示例

$cache['var1'] = $value1;  // equivalent to: $cache->set('var1', $value1);
$value2 = $cache['var2'];  // equivalent to: $value2 = $cache->get('var2');

缓存键

存储在缓存中的每个数据项都由一个键唯一标识。当您将数据项存储在缓存中时,必须为其指定一个键。稍后,当您从缓存中检索数据项时,应提供相应的键。

您可以使用字符串或任意值作为缓存键。当键不是字符串时,它将自动序列化为字符串。

定义缓存键的一种常见策略是将所有确定因素包含在数组中。例如,yii\db\Schema 使用以下键来缓存数据库表的架构信息

[
    __CLASS__,              // schema class name
    $this->db->dsn,         // DB connection data source name
    $this->db->username,    // DB connection login user
    $name,                  // table name
];

如您所见,该键包含唯一指定数据库表所需的所有必要信息。

注意:通过 multiSet()multiAdd() 存储在缓存中的值只能具有字符串或整数键。如果您需要设置更复杂的键,请通过 set()add() 分别存储值。

当不同的应用程序使用相同的缓存存储时,应为每个应用程序指定唯一的缓存键前缀以避免缓存键冲突。这可以通过配置 yii\caching\Cache::$keyPrefix 属性来完成。例如,在应用程序配置中,您可以编写以下代码

'components' => [
    'cache' => [
        'class' => 'yii\caching\ApcCache',
        'keyPrefix' => 'myapp',       // a unique cache key prefix
    ],
],

为了确保互操作性,应仅使用字母数字字符。

缓存过期

存储在缓存中的数据项将永远保留在那里,除非由于某些缓存策略执行(例如缓存空间已满且最旧的数据被删除)而被删除。要更改此行为,您可以在调用 set() 以存储数据项时提供一个过期参数。该参数指示数据项在缓存中可以保持有效多长时间。当您调用 get() 以检索数据项时,如果已超过过期时间,则该方法将返回 false,表示在缓存中找不到数据项。例如,

// keep the data in cache for at most 45 seconds
$cache->set($key, $data, 45);

sleep(50);

$data = $cache->get($key);
if ($data === false) {
    // $data is expired or is not found in the cache
}

从 2.0.11 开始,如果您希望使用自定义缓存持续时间而不是默认的无限持续时间,则可以在缓存组件配置中设置 defaultDuration 值。这将允许您无需每次都将自定义 duration 参数传递给 set()

缓存依赖项

除了过期设置外,缓存数据项也可能因所谓的缓存依赖项的变化而失效。例如,yii\caching\FileDependency 表示文件修改时间的依赖项。当此依赖项更改时,表示相应的文件已修改。结果,缓存中找到的任何过时的文件内容都应失效,并且 get() 调用应返回 false

缓存依赖项表示为 yii\caching\Dependency 后代类的对象。当您调用 set() 以将数据项存储在缓存中时,您可以传递关联的缓存依赖项对象。例如,

// Create a dependency on the modification time of file example.txt.
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);

// The data will expire in 30 seconds.
// It may also be invalidated earlier if example.txt is modified.
$cache->set($key, $data, 30, $dependency);

// The cache will check if the data has expired.
// It will also check if the associated dependency was changed.
// It will return false if any of these conditions are met.
$data = $cache->get($key);

以下是可用缓存依赖项的摘要

注意:避免将 exists() 方法与依赖项一起使用。它不检查与缓存数据关联的依赖项(如果有)是否已更改。因此,对 get() 的调用可能会返回 false,而 exists() 返回 true

查询缓存

查询缓存是构建在数据缓存之上的特殊缓存功能。它用于缓存数据库查询的结果。

查询缓存需要一个 DB 连接 和一个有效的 cache 应用程序组件。查询缓存的基本用法如下所示,假设 $db 是一个 yii\db\Connection 实例

$result = $db->cache(function ($db) {

    // the result of the SQL query will be served from the cache
    // if query caching is enabled and the query result is found in the cache
    return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();

});

查询缓存可用于 DAO 以及 ActiveRecord

$result = Customer::getDb()->cache(function ($db) {
    return Customer::find()->where(['id' => 1])->one();
});

信息:某些 DBMS(例如 MySQL)还在 DB 服务器端支持查询缓存。您可以选择使用任一查询缓存机制。上面描述的查询缓存的优势在于,您可以指定灵活的缓存依赖项,并且可能效率更高。

从 2.0.14 开始,您可以使用以下快捷方式

(new Query())->cache(7200)->all();
// and
User::find()->cache(7200)->all();

配置

查询缓存通过 yii\db\Connection 具有三个全局可配置选项

  • enableQueryCache:是否开启或关闭查询缓存。默认为 true。请注意,要有效地开启查询缓存,您还需要拥有一个有效的缓存,如 queryCache 中所指定。
  • queryCacheDuration:表示查询结果在缓存中可以保持有效多长时间。您可以使用 0 表示查询结果应永远保留在缓存中。此属性是在不指定持续时间的情况下调用 yii\db\Connection::cache() 时使用的默认值。
  • queryCache:表示缓存应用程序组件的 ID。默认为 'cache'。只有存在有效的缓存应用程序组件时,才会启用查询缓存。

用法

如果您有多个需要利用查询缓存的 SQL 查询,则可以使用 yii\db\Connection::cache()。用法如下,

$duration = 60;     // cache query results for 60 seconds.
$dependency = ...;  // optional dependency

$result = $db->cache(function ($db) {

    // ... perform SQL queries here ...

    return $result;

}, $duration, $dependency);

匿名函数中的任何 SQL 查询都将根据指定的持续时间和依赖项进行缓存。如果在缓存中找到查询结果有效,则将跳过该查询,并从缓存中提供结果。如果未指定$duration参数,则将使用queryCacheDuration的值。

有时在cache()中,您可能希望禁用某些特定查询的查询缓存。在这种情况下,可以使用yii\db\Connection::noCache()

$result = $db->cache(function ($db) {

    // SQL queries that use query caching

    $db->noCache(function ($db) {

        // SQL queries that do not use query caching

    });

    // ...

    return $result;
});

如果您只想对单个查询使用查询缓存,则可以在构建命令时调用yii\db\Command::cache()。例如:

// use query caching and set query cache duration to be 60 seconds
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();

您还可以使用yii\db\Command::noCache()禁用单个命令的查询缓存。例如:

$result = $db->cache(function ($db) {

    // SQL queries that use query caching

    // do not use query caching for this command
    $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne();

    // ...

    return $result;
});

限制

查询缓存不适用于包含资源处理程序的查询结果。例如,在某些 DBMS 中使用BLOB列类型时,查询结果将返回该列数据的资源处理程序。

某些缓存存储具有大小限制。例如,memcache 将每个条目的最大大小限制为 1MB。因此,如果查询结果的大小超过此限制,则缓存将失败。

缓存刷新

当您需要使所有存储的缓存数据失效时,可以调用yii\caching\Cache::flush()

您也可以通过调用yii cache/flush从控制台刷新缓存。

  • yii cache:列出应用程序中可用的缓存。
  • yii cache/flush cache1 cache2:刷新缓存组件cache1cache2(您可以使用空格分隔多个组件名称)。
  • yii cache/flush-all:刷新应用程序中的所有缓存组件。
  • yii cache/flush-schema db:清除给定连接组件的数据库模式缓存。

信息:控制台应用程序默认使用单独的配置文件。确保您的 Web 和控制台应用程序配置文件中具有相同的缓存组件,以达到预期的效果。

发现错别字或您认为此页面需要改进?
在 github 上编辑它 !