|
|
|
Кэширование данных
|
|
|
|
==================
|
|
|
|
|
|
|
|
Кэширование данных заключается в сохранении некоторой переменной PHP в кэше и последующее её извлечение. Оно является
|
|
|
|
основой для расширенных возможностей, таких как [кэширование запросов](#query-caching)
|
|
|
|
и [кэширование страниц](caching-page.md).
|
|
|
|
|
|
|
|
Приведённый ниже код является типичным случаем кэширования данных, где `$cache` указывает на [компонент кэширования](#cache-components):
|
|
|
|
|
|
|
|
```php
|
|
|
|
// Пробуем извлечь $data из кэша.
|
|
|
|
$data = $cache->get($key);
|
|
|
|
|
|
|
|
if ($data === false) {
|
|
|
|
|
|
|
|
// $data нет в кэше, считаем с нуля.
|
|
|
|
|
|
|
|
// Сохраняем значение $data в кэше. Данные можно получить в следующий раз.
|
|
|
|
$cache->set($key, $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Значение $data доступно здесь.
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Компоненты кэширования <span id="cache-components"></span>
|
|
|
|
|
|
|
|
Кэширование данных опирается на *компоненты кэширования*, которые представляют различные хранилища, такие как память,
|
|
|
|
файлы и базы данных.
|
|
|
|
|
|
|
|
Кэш-компоненты, как правило, зарегистрированы в качестве [компонентов приложения](structure-application-components.md), так
|
|
|
|
что их можно настраивать и обращаться к ним глобально. Следующий код показывает, как настроить компонент приложения `cache`
|
|
|
|
для использования [Memcached](http://memcached.org/) с двумя серверами:
|
|
|
|
|
|
|
|
```php
|
|
|
|
'components' => [
|
|
|
|
'cache' => [
|
|
|
|
'class' => 'yii\caching\MemCache',
|
|
|
|
'servers' => [
|
|
|
|
[
|
|
|
|
'host' => 'server1',
|
|
|
|
'port' => 11211,
|
|
|
|
'weight' => 100,
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'host' => 'server2',
|
|
|
|
'port' => 11211,
|
|
|
|
'weight' => 50,
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
```
|
|
|
|
|
|
|
|
Вы можете получить доступ к компоненту кэша, используя выражение `Yii::$app->cache`.
|
|
|
|
|
|
|
|
Поскольку все компоненты кэша поддерживают единый API-интерфейс, вы можете менять основной компонент кэша на другой
|
|
|
|
через конфигурацию приложения. Код, использующий кэш, при этом не меняется. Например, конфигурацию выше для использования
|
|
|
|
[[yii\caching\ApcCache|APC cache]] можно изменить следующим образом:
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
'components' => [
|
|
|
|
'cache' => [
|
|
|
|
'class' => 'yii\caching\ApcCache',
|
|
|
|
],
|
|
|
|
],
|
|
|
|
```
|
|
|
|
|
|
|
|
> Совет: Вы можете зарегистрировать несколько кэш-компонентов приложения. Компонент с именем `cache` используется
|
|
|
|
по умолчанию многими классами (например, [[yii\web\UrlManager]]).
|
|
|
|
|
|
|
|
|
|
|
|
### Поддерживаемые хранилища <span id="supported-cache-storage"></span>
|
|
|
|
|
|
|
|
Yii поддерживает множество хранилищ кэша:
|
|
|
|
|
|
|
|
* [[yii\caching\ApcCache]]: использует расширение PHP [APC](http://php.net/manual/en/book.apc.php). Эта опция считается
|
|
|
|
самой быстрой при работе с кэшем в «толстом» централизованном приложении (т.е. один сервер, без выделенного
|
|
|
|
балансировщика нагрузки и т.д.).
|
|
|
|
* [[yii\caching\DbCache]]: использует таблицу базы данных для хранения кэшированных данных. Чтобы использовать этот кэш,
|
|
|
|
вы должны создать таблицу, как описано в [[yii\caching\DbCache::cacheTable]].
|
|
|
|
* [[yii\caching\DummyCache]]: является кэшем-пустышкой, не реализующим реального кэширования. Смысл этого компонента в
|
|
|
|
упрощении кода, который должен проверить наличие кэша. Вы можете использовать данный тип кэша, например, при разработке
|
|
|
|
или если сервер не поддерживает кэш и переключиться на реальное кэширование позже. Для извлечения данных, в этом случае,
|
|
|
|
используется один и тот же код `Yii::$app->cache->get($key)`. При этом можно не беспокоиться, что `Yii::$app->cache`
|
|
|
|
может быть `null`.
|
|
|
|
* [[yii\caching\FileCache]]: использует обычные файлы для хранения кэшированных данных. Замечательно подходит для
|
|
|
|
кэширования больших кусков данных, таких как содержимое страницы.
|
|
|
|
* [[yii\caching\MemCache]]: использует расширения PHP [memcache](http://php.net/manual/en/book.memcache.php)
|
|
|
|
и [memcached](http://php.net/manual/en/book.memcached.php). Этот вариант может рассматриваться как самый быстрый при
|
|
|
|
работе в распределенных приложениях (например, с несколькими серверами, балансировкой нагрузки и так далее).
|
|
|
|
* [[yii\redis\Cache]]: реализует компонент кэша на основе [Redis](http://redis.io/), хранилища ключ-значение (требуется
|
|
|
|
Redis версии 2.6.12 или выше).
|
|
|
|
* [[yii\caching\WinCache]]: использует расширение PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension)
|
|
|
|
([смотрите также](http://php.net/manual/en/book.wincache.php)) .
|
|
|
|
* [[yii\caching\XCache]]: использует расширение PHP [XCache](http://xcache.lighttpd.net/).
|
|
|
|
* [[yii\caching\ZendDataCache]]: использует
|
|
|
|
[Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm).
|
|
|
|
|
|
|
|
|
|
|
|
> Совет: Вы можете использовать разные способы хранения кэша в одном приложении. Общая стратегия заключается в использовании
|
|
|
|
памяти под хранение небольших часто используемых данных (например, статистические данные). Для больших и реже используемых
|
|
|
|
данных (например, содержимое страницы) лучше использовать файлы или базу данных.
|
|
|
|
|
|
|
|
|
|
|
|
## Кэш API, <a name="cache-apis"> </a>
|
|
|
|
|
|
|
|
У всех компонентов кэша один базовый класс [[yii\caching\Cache]] со следующими методами:
|
|
|
|
|
|
|
|
* [[yii\caching\Cache::get()|get()]]: возвращает данные по указанному ключу. Значение `false`
|
|
|
|
будет возвращено, если данные не найдены или устарели.
|
|
|
|
* [[yii\caching\Cache::set()|set()]]: сохраняет данные по ключу.
|
|
|
|
* [[yii\caching\Cache::add()|add()]]: сохраняет данные по ключу если такого ключа ещё нет.
|
|
|
|
* [[yii\caching\Cache::mget()|mget()]]: извлекает сразу несколько элементов данных из кэша по заданным ключам.
|
|
|
|
* [[yii\caching\Cache::mset()|mset()]]: сохраняет несколько элементов данных. Каждый элемент идентифицируется ключом.
|
|
|
|
* [[yii\caching\Cache::madd()|madd()]]: сохраняет несколько элементов данных. Каждый элемент идентифицируется ключом.
|
|
|
|
Если ключ уже существует, сохранение не происходит.
|
|
|
|
* [[yii\caching\Cache::exists()|exists()]]: есть ли указанный ключ в кэше.
|
|
|
|
* [[yii\caching\Cache::delete()|delete()]]: удаляет указанный ключ.
|
|
|
|
* [[yii\caching\Cache::flush()|flush()]]: удаляет все данные.
|
|
|
|
|
|
|
|
> Примечание: Не кэшируйте непосредственно значение `false`, потому что [[yii\caching\Cache::get()|get()]] использует
|
|
|
|
`false` для случая, когда данные не найдены в кэше. Вы можете обернуть `false` в массив и закэшировать его, чтобы
|
|
|
|
избежать данной проблемы.
|
|
|
|
|
|
|
|
Некоторые кэш-хранилища, например, MemCache или APC, поддерживают получение нескольких значений в пакетном режиме,
|
|
|
|
что может сократить накладные расходы на получение данных. Данную возможность можно использовать при помощи
|
|
|
|
[[yii\caching\Cache::mget()|mget()]] и [[yii\caching\Cache::madd()|madd()]]. В случае, если хранилище не поддерживает
|
|
|
|
эту функцию, она будет имитироваться.
|
|
|
|
|
|
|
|
Так как [[yii\caching\Cache]] реализует `ArrayAccess`, компонент кэша можно испльзовать как массив:
|
|
|
|
|
|
|
|
```php
|
|
|
|
$cache['var1'] = $value1; // эквивалентно: $cache->set('var1', $value1);
|
|
|
|
$value2 = $cache['var2']; // эквивалентно: $value2 = $cache->get('var2');
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Ключи кэша <span id="cache-keys"></span>
|
|
|
|
|
|
|
|
Каждый элемент данных, хранящийся в кэше, идентифицируется ключом. Когда вы сохраняете элемент данных в кэше, необходимо
|
|
|
|
указать для него ключ. Позже, когда вы извлекаете элемент данных из кэша, вы должны предоставить соответствующий ключ.
|
|
|
|
|
|
|
|
Вы можете использовать строку или произвольное значение в качестве ключа кэша. Если ключ не строка, то он будет
|
|
|
|
автоматически сериализован в строку.
|
|
|
|
|
|
|
|
Обычно ключ задаётся массивом всех значимых частей. Например, для хранении информации о таблице в [[yii\db\Schema]]
|
|
|
|
для ключа используются следующие части:
|
|
|
|
|
|
|
|
```php
|
|
|
|
[
|
|
|
|
__CLASS__, // Название класса схемы.
|
|
|
|
$this->db->dsn, // Данные для соединения с базой.
|
|
|
|
$this->db->username, // Логин для соединения с базой.
|
|
|
|
$name, // Название таблицы.
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
Как вы можете видеть, ключ строится так, чтобы однозначно идентифицировать данные таблицы.
|
|
|
|
|
|
|
|
Если одно хранилище кэша используется несколькими приложениями, во избежание конфликтов стоит указать префикс ключа.
|
|
|
|
Сделать это можно путём настройки [[yii\caching\Cache::keyPrefix]]:
|
|
|
|
|
|
|
|
```php
|
|
|
|
'components' => [
|
|
|
|
'cache' => [
|
|
|
|
'class' => 'yii\caching\ApcCache',
|
|
|
|
'keyPrefix' => 'myapp', // уникальный префикс ключей кэша
|
|
|
|
],
|
|
|
|
],
|
|
|
|
```
|
|
|
|
|
|
|
|
Для обеспечения совместимости должны быть использованы только алфавитно-цифровые символы.
|
|
|
|
|
|
|
|
|
|
|
|
### Срок действия кэша <span id="cache-expiration"></span>
|
|
|
|
|
|
|
|
Элементы данных, хранимые в кэше, остаются там навсегда если только они не будут удалены из-за особенностей
|
|
|
|
функционирования хранилища (например, место для кэширования заполнено и старые данные удаляются). Чтобы изменить этот
|
|
|
|
режим, вы можете передать истечение срока действия ключа при вызове метода [[yii\caching\Cache::set()|set()]].
|
|
|
|
Параметр указывает, сколько секунд элемент кэша может считаться актуальным. Если срок годности ключа истёк,
|
|
|
|
[[yii\caching\Cache::get()|get()]] вернёт `false`:
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
// Хранить данные в кэше не более 45 секунд
|
|
|
|
$cache->set($key, $data, 45);
|
|
|
|
|
|
|
|
sleep(50);
|
|
|
|
|
|
|
|
$data = $cache->get($key);
|
|
|
|
if ($data === false) {
|
|
|
|
// срок действия истек или ключ не найден в кэше
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Зависимости кэша <span id="cache-dependencies"></span>
|
|
|
|
|
|
|
|
В добавок к изменеию срока действия ключа, элемент может быть признан недействительным из-за *изменения зависимостей*.
|
|
|
|
К примеру, [[yii\caching\FileDependency]] представляет собой зависимость от времени изменения файла. Когда это время
|
|
|
|
изменяется, и файл. Любые устаревшие данные, найденные в кэше должны быть признаны недействительным, а
|
|
|
|
[[yii\caching\Cache::get()|get()]] в этом случае должен вернуть `false`.
|
|
|
|
|
|
|
|
Зависимости кэша представлены в виде объектов потомков класса [[yii\caching\Dependency]]. Когда вы вызываете метод
|
|
|
|
[[yii\caching\Cache::set()|set()]], чтобы сохранить элемент данных в кэше, вы можете передать туда зависимость. Например:
|
|
|
|
|
|
|
|
```php
|
|
|
|
// Создать зависимость от времени модификации файла example.txt.
|
|
|
|
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);
|
|
|
|
|
|
|
|
// Данные устаревеют через 30 секунд.
|
|
|
|
// Данные могут устареть и раньше, если example.txt будет изменён.
|
|
|
|
$cache->set($key, $data, 30, $dependency);
|
|
|
|
|
|
|
|
// Кэш будет проверен, если данные устарели.
|
|
|
|
// Он также будет проверен, если указанная зависимость была изменена.
|
|
|
|
// Вернется false, если какое-либо из этих условий выполнено.
|
|
|
|
$data = $cache->get($key);
|
|
|
|
```
|
|
|
|
|
|
|
|
Ниже приведен список доступных зависимостей кэша:
|
|
|
|
|
|
|
|
- [[yii\caching\ChainedDependency]]: зависимость меняется, если любая зависимость в цепочке изменяется.
|
|
|
|
- [[yii\caching\DbDependency]]: зависимость меняется, если результат некоторого определенного SQL запроса изменён.
|
|
|
|
- [[yii\caching\ExpressionDependency]]: зависимость меняется, если результат определенного PHP выражения изменён.
|
|
|
|
- [[yii\caching\FileDependency]]: зависимость меняется, если изменилось время последней модификации файла.
|
|
|
|
- [[yii\caching\TagDependency]]: Связывает кэшированные данные элемента с одним или несколькими тегами. Вы можете
|
|
|
|
аннулировать кэширование данных элементов с заданным тегом(тегами) по вызову. [[yii\caching\TagDependency::invalidate()]].
|
|
|
|
|
|
|
|
|
|
|
|
## Кэширование запросов <span id="query-caching"></span>
|
|
|
|
|
|
|
|
Кэширование запросов - это специальная функция кэширования, построеная на основе кэширования данных.
|
|
|
|
Она предназначена для кэширования результатов запросов к базе данных.
|
|
|
|
|
|
|
|
Кэширование запросов требует [[yii\db\Connection|DB connection]] и приложения действительный `cache`. Простое использование
|
|
|
|
запросов кэширования происходит следующим образом, предпологая что `$db` это экземпляр [[yii\db\Connection]]:
|
|
|
|
|
|
|
|
```php
|
|
|
|
$result = $db->cache(function ($db) {
|
|
|
|
|
|
|
|
// Результат SQL запроса будет возвращен из кэша если
|
|
|
|
// кэширование запросов включено и результат запроса присутствует в кэше
|
|
|
|
return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
|
|
|
|
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
Кэширование запросов может быть использованно как для [DAO](db-dao.md), так и для [ActiveRecord](db-active-record.md).
|
|
|
|
|
|
|
|
> Информация: Некоторые СУБД (например, [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html)) поддерживают
|
|
|
|
кэширование запросов на стороне сервера БД. Вы можете использовать любой механизм кэширования запросов. Кэширование
|
|
|
|
запросов описанное выше, имеет преимущество, поскольку можно указать гибкие зависимости кэша и это более эффективно.
|
|
|
|
|
|
|
|
|
|
|
|
### Конфигурации <span id="query-caching-configs"></span>
|
|
|
|
|
|
|
|
Кэширование запросов имеет три глобальных конфигурационных параметра через [[yii\db\Connection]]:
|
|
|
|
|
|
|
|
* [[yii\db\Connection::enableQueryCache|enableQueryCache]]: включить или выключить кэширование запросов.
|
|
|
|
По умолчанию `true`. Стоит отметить, что для использования кэширования вам может понадобиться компонент
|
|
|
|
cache, как показано в [[yii\db\Connection::queryCache|queryCache]].
|
|
|
|
* [[yii\db\Connection::queryCacheDuration|queryCacheDuration]]: количество секунд, в течение которых результат кэшируется.
|
|
|
|
Для бесконечного кэша используйте `0`. Именно это значение выставляется [[yii\db\Connection::cache()]] если не указать
|
|
|
|
время явно.
|
|
|
|
* [[yii\db\Connection::queryCache|queryCache]]: ID компонента кэширования. По умолчанию `'cache'`. Кэширования запросов
|
|
|
|
работает только если используется компонент приложения кэш.
|
|
|
|
|
|
|
|
|
|
|
|
### Использование <span id="query-caching-usages"></span>
|
|
|
|
|
|
|
|
Вы можете использовать [[yii\db\Connection::cache()]], если у вас есть несколько SQL запросов, которые необходимо
|
|
|
|
закэшировать:
|
|
|
|
|
|
|
|
```php
|
|
|
|
$duration = 60; // кэширование результата на 60 секунд
|
|
|
|
$dependency = ...; // параметры зависимости
|
|
|
|
|
|
|
|
$result = $db->cache(function ($db) {
|
|
|
|
|
|
|
|
// ... выполнять SQL запросы здесь ...
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
|
|
|
}, $duration, $dependency);
|
|
|
|
```
|
|
|
|
|
|
|
|
Любые SQL запросы в анонимной функции будут кэшироваться в течении указанного промежутка времени с заданной зависимостью.
|
|
|
|
Если результат в кэше актуален, запрос будет пропущен и, вместо этого, из кэша будет возвращен результат. Если вы не
|
|
|
|
укажете `'$duration'`, значение [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] будет использоваться вместо него.
|
|
|
|
|
|
|
|
Иногда в пределах `"cache()"` вы можете отключить кэширование запроса. В этом случае вы можете использовать
|
|
|
|
[[yii\db\Connection::noCache()]].
|
|
|
|
|
|
|
|
```php
|
|
|
|
$result = $db->cache(function ($db) {
|
|
|
|
|
|
|
|
// SQL запросы, которые используют кэширование
|
|
|
|
|
|
|
|
$db->noCache(function ($db) {
|
|
|
|
|
|
|
|
// SQL запросы, которые не используют кэширование
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
Если вы просто хотите использовать кэширование для одного запроса, вы можете вызвать [[yii\db\Command::cache()]] при
|
|
|
|
построении конманды. Например:
|
|
|
|
|
|
|
|
```php
|
|
|
|
// использовать кэширование запросов и установить срок действия кэша на 60 секунд
|
|
|
|
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
|
|
|
|
```
|
|
|
|
|
|
|
|
Вы также можете использовать [[yii\db\Command::noCache()]], чтобы отключить кэширование запросов для одной команды. Например:
|
|
|
|
|
|
|
|
```php
|
|
|
|
$result = $db->cache(function ($db) {
|
|
|
|
|
|
|
|
// Используется кэширование SQL запросов
|
|
|
|
|
|
|
|
// не использовать кэширование запросов для этой команды
|
|
|
|
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne();
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Ограничения <span id="query-caching-limitations"></span>
|
|
|
|
|
|
|
|
Кэширование запросов не работает с результатами запросов, которые содержат обработчики ресурсов. Например, при использовании
|
|
|
|
типа столбца `BLOB` в некоторых СУБД, в качестве результата запроса будет выведен ресурс обработчик данных столбца.
|
|
|
|
|
|
|
|
Некоторые кэш хранилища имеют ограничение в размере данных. Например, Memcache ограничивает максимальный размер каждой
|
|
|
|
записи до 1 Мб. Таким образом, если результат запроса превышает этот предел, данные не будут закэшированны.
|