mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-06 16:16:53 +01:00
257 lines
15 KiB
Plaintext
257 lines
15 KiB
Plaintext
Кэширование данных
|
||
==================
|
||
|
||
Кэширование данных — это сохранение некоторой переменной PHP в кэше и последующее её извлечение
|
||
оттуда. Для этой цели базовый класс компонентов кэширования [CCache]
|
||
предоставляет два наиболее используемых метода: [set()|CCache::set]
|
||
и [get()|CCache::get].
|
||
|
||
Для кэширования переменной `$value` мы выбираем уникальный идентификатор (ID)
|
||
и вызываем метод [set()|CCache::set] для её сохранения в кэше:
|
||
|
||
~~~
|
||
[php]
|
||
Yii::app()->cache->set($id, $value);
|
||
~~~
|
||
|
||
Данные будут оставаться в кэше до тех пор, пока не будут удалены
|
||
согласно некоторой политике кэширования (например, если места для хранения кэшированых
|
||
данных не осталось, тогда самые старые данные удаляются).
|
||
Чтобы изменить это поведение, мы можем установить срок действия кэша при вызове
|
||
метода [set()|CCache::set]. В этом случае данные будут удалены из кэша по истечении
|
||
определённого периода времени:
|
||
|
||
~~~
|
||
[php]
|
||
// храним значение переменной в кэше не более 30 секунд
|
||
Yii::app()->cache->set($id, $value, 30);
|
||
~~~
|
||
|
||
Позже, когда нам требуется обратиться к этой переменной (при обработке текущего или другого веб-запроса),
|
||
мы вызываем метод [get()|CCache::get] с указанным идентификатором, чтобы получить её значение из кэша.
|
||
Если будет возвращено значение false, то это означает, что переменная
|
||
не доступна в кэше, и мы должны заново создать её.
|
||
|
||
~~~
|
||
[php]
|
||
$value=Yii::app()->cache->get($id);
|
||
if($value===false)
|
||
{
|
||
// устанавливаем значение $value заново, т.к. оно не найдено в кэше,
|
||
// и сохраняем его в кэше для дальнейшего использования:
|
||
// Yii::app()->cache->set($id,$value);
|
||
}
|
||
~~~
|
||
|
||
При выборе идентификатора для кэшируемой переменной учитывайте, что он
|
||
должен быть уникальным для каждой переменной из тех, что могут быть
|
||
кэшированы в приложении. *НЕ* требуется, чтобы идентификатор был уникальным
|
||
среди нескольких приложений, компонент кэширования достаточно умён для
|
||
различения идентификаторов разных приложений.
|
||
|
||
Некоторые кэш-хранилища, такие как MemCache и APC, поддерживают извлечение
|
||
нескольких кэшированных значений в пакетном режиме, что может уменьшить
|
||
накладные расходы при извлечении данных из кэша. Метод [mget()|CCache::mget]
|
||
позволяет использовать эту возможность. В случае если кэш-хранилище не поддерживает
|
||
такую возможность, [mget()|CCache::mget] будет тем не менее имитировать её.
|
||
|
||
Для удаления значения из кэша необходимо вызвать метод
|
||
[delete()|CCache::delete], а для очистки всего кэша — метод
|
||
[flush()|CCache::flush]. Следует быть осторожным при вызове метода
|
||
[flush()|CCache::flush], т.к. он также удаляет кэшированные данные
|
||
других приложений.
|
||
|
||
> Tip|Подсказка: класс [CCache] реализует интерфейс `ArrayAccess`, поэтому
|
||
> компонент кэширования может использоваться как массив. Ниже приведены примеры:
|
||
> ~~~
|
||
> [php]
|
||
> $cache=Yii::app()->cache;
|
||
> $cache['var1']=$value1; // эквивалентно $cache->set('var1',$value1);
|
||
> $value2=$cache['var2']; // эквивалентно $value2=$cache->get('var2');
|
||
> ~~~
|
||
|
||
Зависимость кэша
|
||
----------------
|
||
|
||
Помимо установки срока действия, кэшируемые данные также могут стать
|
||
недействительными в соответствии с некоторыми изменениями зависимости
|
||
(dependency).
|
||
Например, если мы кэшируем содержимое некоторого файла, и файл изменился,
|
||
мы должны считать кэшированную копию недействительной и извлечь свежее
|
||
содержимое из файла, а не из кэша.
|
||
|
||
Мы представляем зависимость как экземпляр класса [CCacheDependency] или
|
||
одного из его наследников. Мы передаём экземпляр зависимости вместе с
|
||
кэшируемыми данными, когда вызываем метод [set()|CCache::set].
|
||
|
||
~~~
|
||
[php]
|
||
// значение действительно не более 30 секунд
|
||
// кроме того, значение может стать недействительным раньше, если зависимый файл изменился
|
||
Yii::app()->cache->set($id, $value, 30, new CFileCacheDependency('FileName'));
|
||
~~~
|
||
|
||
Теперь, если мы попытаемся извлечь значение `$value` из кэша, вызвав метод
|
||
[get()|CCache::get], зависимость будет проверена и, если она изменилась, мы
|
||
получим значение false, означающее, что данные требуют обновления.
|
||
|
||
Ниже приведён список доступных зависимостей кэша:
|
||
|
||
- [CFileCacheDependency]: зависимость меняется, если время последней модификации файла
|
||
изменилось.
|
||
|
||
- [CDirectoryCacheDependency]: зависимость меняется, если любой файл в
|
||
каталоге или в подкаталогах изменился.
|
||
|
||
- [CDbCacheDependency]: зависимость меняется, если результат запроса
|
||
некоторого определённого SQL-выражения изменился.
|
||
|
||
- [CGlobalStateCacheDependency]: зависимость меняется, если значение
|
||
определённого глобального состояния изменилось. Глобальное состояние —
|
||
это переменная, являющаяся постоянной в многократных запросах и сессиях
|
||
приложения. Её значение устанавливается с помощью метода [CApplication::setGlobalState()].
|
||
|
||
- [CChainedCacheDependency]: зависимость меняется, если любая зависимость
|
||
цепочки изменилась.
|
||
|
||
- [CExpressionDependency]: зависимость меняется, если результат
|
||
определённого PHP выражения изменился.
|
||
|
||
Кэширование запросов
|
||
--------------------
|
||
|
||
Начиная с версии 1.1.7, Yii поддерживает кэширование запросов. Построенное на
|
||
кэшировании данных, кэширование запросов хранит результат запроса к базе
|
||
данных в кэше и, тем самым, экономит время, расходуемое на одни и те же запросы.
|
||
|
||
> Info|Информация: Некоторые СУБД, такие как
|
||
> [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html),
|
||
> поддерживают кэширование на стороне сервера базы данных.
|
||
> Аналогичная возможность в Yii обеспечивает большую гибкость по сравнению с кэшированием на стороне сервера БД, и
|
||
> потенциально она более эффективна.
|
||
|
||
|
||
### Включение кэширования запросов
|
||
|
||
Для того чтобы включить кэширование запросов, убедитесь, что
|
||
[CDbConnection::queryCacheID] содержит ID подключённого компонента,
|
||
отвечающего за кэширование. По умолчанию это компонент `cache`.
|
||
|
||
|
||
### Использование кэширования запросов с DAO
|
||
|
||
Для того чтобы использовать кэширование запросов, необходимо вызвать
|
||
метод [CDbConnection::cache()], как показано ниже:
|
||
|
||
~~~
|
||
[php]
|
||
$sql = 'SELECT * FROM tbl_post LIMIT 20';
|
||
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
|
||
$rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();
|
||
~~~
|
||
|
||
При выполнении приведённого кода Yii сначала проверит, есть ли в кэше актуальный
|
||
результат, соответствующий SQL-запросу, который мы собираемся выполнить. При этом
|
||
проверяются следующие три условия:
|
||
|
||
- есть ли в кэше данные с запросом в качестве индекса;
|
||
- не являются ли данные устаревшими (должно пройти менее 1000 секунд с момента последней записи в кэш);
|
||
- не изменилась ли зависимость кэша (максимальное значение `update_time` осталось тем же, каким
|
||
было при сохранении результата запроса в кэш).
|
||
|
||
Если все три условия выполнены, то результат берётся из кэша. Иначе выполняется
|
||
SQL-запрос, его результат записывается в кэш и возвращается.
|
||
|
||
|
||
### Использование кеширования запросов с ActiveRecord
|
||
|
||
Кэширование запросов также можно использовать совместно с [Active Record](/doc/guide/database.ar).
|
||
Для этого мы используем метод [CActiveRecord::cache()]:
|
||
|
||
~~~
|
||
[php]
|
||
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
|
||
$posts = Post::model()->cache(1000, $dependency)->findAll();
|
||
// реляционный запрос
|
||
$posts = Post::model()->cache(1000, $dependency)->with('author')->findAll();
|
||
~~~
|
||
|
||
Метод `cache()` является сокращением для вызова [CDbConnection::cache()].
|
||
При выполнении SQL-запроса, сгенерированного ActiveRecord, Yii попытается
|
||
использовать кэширование так же, как это было описано в предыдущем подразделе.
|
||
|
||
|
||
### Кэширование нескольких запросов
|
||
|
||
По умолчанию, каждый раз, когда мы вызываем метод `cache()` (класса [CDbConnection]
|
||
или [CActiveRecord]), он кэширует только следующий за его вызовом SQL-запрос. Все остальные
|
||
запросы НЕ кэшируются, пока мы не вызовем `cache()` ещё раз. Например:
|
||
|
||
~~~
|
||
[php]
|
||
$sql = 'SELECT * FROM tbl_post LIMIT 20';
|
||
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
|
||
|
||
$rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();
|
||
// запрос НЕ БУДЕТ закэширован
|
||
$rows = Yii::app()->db->createCommand($sql)->queryAll();
|
||
~~~
|
||
|
||
Передавая методу `cache()` дополнительный параметр `$queryCount`, мы можем
|
||
закэшировать несколько подряд выполняющихся запросов. В следующем примере мы кэшируем
|
||
два запроса:
|
||
|
||
~~~
|
||
[php]
|
||
// ...
|
||
$rows = Yii::app()->db->cache(1000, $dependency, 2)->createCommand($sql)->queryAll();
|
||
// запрос БУДЕТ закэширован
|
||
$rows = Yii::app()->db->createCommand($sql)->queryAll();
|
||
~~~
|
||
|
||
Как известно, при выполнении реляционного AR-запроса, на самом деле могут выполняться
|
||
несколько SQL-запросов (это можно узнать,
|
||
проверив [журнал сообщений](/doc/guide/topics.logging)). Например, если
|
||
связь между `Post` и `Comment` типа `HAS_MANY`, то код, приведённый ниже,
|
||
выполнит два запроса:
|
||
|
||
- сначала будут выбраны 20 записей;
|
||
- после этого будут выбраны комментарии для этих записей.
|
||
|
||
~~~
|
||
[php]
|
||
$posts = Post::model()->with('comments')->findAll(array(
|
||
'limit'=>20,
|
||
));
|
||
~~~
|
||
|
||
Если использовать кэширование запросов, как показано ниже, закэширован будет
|
||
только первый запрос к БД:
|
||
|
||
~~~
|
||
[php]
|
||
$posts = Post::model()->cache(1000, $dependency)->with('comments')->findAll(array(
|
||
'limit'=>20,
|
||
));
|
||
~~~
|
||
|
||
Для того чтобы в кэш попали оба запроса, необходимо передать дополнительный
|
||
параметр, задающий количество кэшируемых запросов:
|
||
|
||
~~~
|
||
[php]
|
||
$posts = Post::model()->cache(1000, $dependency, 2)->with('comments')->findAll(array(
|
||
'limit'=>20,
|
||
));
|
||
~~~
|
||
|
||
|
||
### Ограничения
|
||
|
||
Кэширование запросов не работает с результатами, содержащими указатели на ресурс.
|
||
Например, указатель возвращается в некоторых СУБД при использовании типа `BLOB`.
|
||
|
||
В некоторых хранилищах кэша есть ограничение на размер хранимых данных.
|
||
Например, в memcache максимальный размер одной единицы данных равен одному
|
||
мегабайту. Поэтому, если размер результата запроса превысит данное ограничение,
|
||
то кэширование не сработает. |