caching-data.md 23.2 KB
Newer Older
Nepster committed
1 2 3
Кэширование данных
==================

4 5
Кэширование данных заключается в сохранении некоторой переменной PHP в кэше и последующее её извлечение. Оно является
основой для расширенных возможностей, таких как [кэширование запросов](#query-caching)
Nepster committed
6 7
и [кэширование страниц](caching-page.md).

Nepster committed
8
Приведённый ниже код является типичным случаем кэширования данных, где `$cache` указывает на [компонент кэширования](#cache-components):
Nepster committed
9 10

```php
11
// Пробуем извлечь $data из кэша.
Nepster committed
12 13 14 15
$data = $cache->get($key);

if ($data === false) {

16
    // $data нет в кэше, считаем с нуля.
Nepster committed
17

18
    // Сохраняем значение $data в кэше. Данные можно получить в следующий раз.
Nepster committed
19 20 21
    $cache->set($key, $data);
}

22
// Значение $data доступно здесь.
Nepster committed
23 24 25
```


26
## Компоненты кэширования <span id="cache-components"></span>
Nepster committed
27

28 29
Кэширование данных опирается на *компоненты кэширования*, которые представляют различные хранилища, такие как память,
файлы и базы данных.
Nepster committed
30 31

Кэш-компоненты, как правило, зарегистрированы в качестве [компонентов приложения](structure-application-components.md), так
32 33
что их можно настраивать и обращаться к ним глобально. Следующий код показывает, как настроить компонент приложения `cache`
для использования [Memcached](http://memcached.org/) с двумя серверами:
Nepster committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

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

55
Вы можете получить доступ к компоненту кэша, используя выражение `Yii::$app->cache`.
Nepster committed
56

57 58 59
Поскольку все компоненты кэша поддерживают единый API-интерфейс, вы можете менять основной компонент кэша на другой
через конфигурацию приложения. Код, использующий кэш, при этом не меняется. Например, конфигурацию выше для использования
[[yii\caching\ApcCache|APC cache]] можно изменить следующим образом:
Nepster committed
60 61 62 63 64 65 66 67 68 69 70


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

> Совет: Вы можете зарегистрировать несколько кэш-компонентов приложения. Компонент с именем `cache` используется 
71
  по умолчанию многими классами (например, [[yii\web\UrlManager]]).
Nepster committed
72 73
   
   
74
### Поддерживаемые хранилища <span id="supported-cache-storage"></span>
75 76 77 78 79 80 81 82 83 84

Yii поддерживает множество хранилищ кэша:

* [[yii\caching\ApcCache]]: использует расширение PHP [APC](http://php.net/manual/en/book.apc.php). Эта опция считается
  самой быстрой при работе с кэшем в «толстом» централизованном приложении (т.е. один сервер, без выделенного
  балансировщика нагрузки и т.д.).
* [[yii\caching\DbCache]]: использует таблицу базы данных для хранения кэшированных данных. Чтобы использовать этот кэш,
  вы должны создать таблицу, как описано в [[yii\caching\DbCache::cacheTable]].
* [[yii\caching\DummyCache]]: является кэшем-пустышкой, не реализующим реального кэширования. Смысл этого компонента в
  упрощении кода, который должен проверить наличие кэша. Вы можете использовать данный тип кэша, например, при разработке
Nepster committed
85
  или если сервер не поддерживает кэш и переключиться на реальное кэширование позже. Для извлечения данных, в этом случае,
86 87 88 89 90 91 92 93 94 95 96 97
  используется один и тот же код `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/).
Nepster committed
98
* [[yii\caching\ZendDataCache]]: использует
99
  [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm).
Nepster committed
100 101


102 103 104
> Совет: Вы можете использовать разные способы хранения кэша в одном приложении. Общая стратегия заключается в использовании
  памяти под хранение небольших часто используемых данных (например, статистические данные). Для больших и реже используемых
  данных (например, содержимое страницы) лучше использовать файлы или базу данных.
Nepster committed
105 106 107 108
  

## Кэш API, <a name="cache-apis"> </a>

109
У всех компонентов кэша один базовый класс [[yii\caching\Cache]] со следующими методами:
Nepster committed
110

111 112 113 114 115 116 117 118 119 120 121
* [[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()]]: удаляет все данные.
Nepster committed
122

123 124 125
> Примечание: Не кэшируйте непосредственно значение `false`, потому что [[yii\caching\Cache::get()|get()]] использует
  `false` для случая, когда данные не найдены в кэше. Вы можете обернуть `false` в массив и закэшировать его, чтобы
  избежать данной проблемы.
Nepster committed
126

127 128 129 130
Некоторые кэш-хранилища, например, MemCache или APC, поддерживают получение нескольких значений в пакетном режиме,
что может сократить накладные расходы на получение данных. Данную возможность можно использовать при помощи
[[yii\caching\Cache::mget()|mget()]] и [[yii\caching\Cache::madd()|madd()]]. В случае, если хранилище не поддерживает
эту функцию, она будет имитироваться.
Nepster committed
131

Nepster committed
132
Так как [[yii\caching\Cache]] реализует `ArrayAccess`, компонент кэша можно испльзовать как массив:
Nepster committed
133 134 135 136 137 138 139

```php
$cache['var1'] = $value1;  // эквивалентно: $cache->set('var1', $value1);
$value2 = $cache['var2'];  // эквивалентно: $value2 = $cache->get('var2');
```


140
### Ключи кэша <span id="cache-keys"></span>
Nepster committed
141

142 143
Каждый элемент данных, хранящийся в кэше, идентифицируется ключом. Когда вы сохраняете элемент данных в кэше, необходимо
указать для него ключ. Позже, когда вы извлекаете элемент данных из кэша, вы должны предоставить соответствующий ключ.
Nepster committed
144

145 146
Вы можете использовать строку или произвольное значение в качестве ключа кэша. Если ключ не строка, то он будет
автоматически сериализован в строку.
Nepster committed
147

148 149
Обычно ключ задаётся массивом всех значимых частей. Например, для хранении информации о таблице в [[yii\db\Schema]]
для ключа используются следующие части:
Nepster committed
150 151 152

```php
[
153 154 155 156
    __CLASS__,              // Название класса схемы.
    $this->db->dsn,         // Данные для соединения с базой.
    $this->db->username,    // Логин для соединения с базой.
    $name,                  // Название таблицы.
Nepster committed
157 158 159
];
```

160
Как вы можете видеть, ключ строится так, чтобы однозначно идентифицировать данные таблицы.
Nepster committed
161

162 163
Если одно хранилище кэша используется несколькими приложениями, во избежание конфликтов стоит указать префикс ключа.
Сделать это можно путём настройки [[yii\caching\Cache::keyPrefix]]:
Nepster committed
164 165 166 167 168

```php
'components' => [
    'cache' => [
        'class' => 'yii\caching\ApcCache',
169
        'keyPrefix' => 'myapp', // уникальный префикс ключей кэша
Nepster committed
170 171 172 173 174 175 176
    ],
],
```

Для обеспечения совместимости должны быть использованы только алфавитно-цифровые символы.


177
### Срок действия кэша <span id="cache-expiration"></span>
Nepster committed
178

179 180 181
Элементы данных, хранимые в кэше, остаются там навсегда если только они не будут удалены из-за особенностей
функционирования хранилища (например, место для кэширования заполнено и старые данные удаляются). Чтобы изменить этот
режим, вы можете передать истечение срока действия ключа при вызове метода [[yii\caching\Cache::set()|set()]].
Nepster committed
182
Параметр указывает, сколько секунд элемент кэша может считаться актуальным. Если срок годности ключа истёк,
183
[[yii\caching\Cache::get()|get()]] вернёт `false`:
Nepster committed
184 185 186 187 188 189 190 191 192 193


```php
// Хранить данные в кэше не более 45 секунд
$cache->set($key, $data, 45);

sleep(50);

$data = $cache->get($key);
if ($data === false) {
194
    // срок действия истек или ключ не найден в кэше
Nepster committed
195 196 197 198
}
```


199
### Зависимости кэша <span id="cache-dependencies"></span>
Nepster committed
200

201 202 203 204
В добавок к изменеию срока действия ключа, элемент может быть признан недействительным из-за *изменения зависимостей*.
К примеру, [[yii\caching\FileDependency]] представляет собой зависимость от времени изменения файла. Когда это время
изменяется, и файл. Любые устаревшие данные, найденные в кэше должны быть признаны недействительным, а
[[yii\caching\Cache::get()|get()]] в этом случае должен вернуть `false`. 
Nepster committed
205

206 207
Зависимости кэша представлены в виде объектов потомков класса [[yii\caching\Dependency]]. Когда вы вызываете метод
[[yii\caching\Cache::set()|set()]], чтобы сохранить элемент данных в кэше, вы можете передать туда зависимость. Например:
Nepster committed
208 209 210 211 212

```php
// Создать зависимость от времени модификации файла example.txt.
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);

213 214
// Данные устаревеют через 30 секунд.
// Данные могут устареть и раньше, если example.txt будет изменён.
Nepster committed
215 216
$cache->set($key, $data, 30, $dependency);

217
// Кэш будет проверен, если данные устарели.
Nepster committed
218 219 220 221 222 223 224 225
// Он также будет проверен, если указанная зависимость была изменена.
// Вернется false, если какое-либо из этих условий выполнено.
$data = $cache->get($key);
```

Ниже приведен список доступных зависимостей кэша:

- [[yii\caching\ChainedDependency]]: зависимость меняется, если любая зависимость в цепочке изменяется.
226 227
- [[yii\caching\DbDependency]]: зависимость меняется, если результат некоторого определенного SQL запроса изменён.
- [[yii\caching\ExpressionDependency]]: зависимость меняется, если результат определенного PHP выражения изменён.
Nepster committed
228
- [[yii\caching\FileDependency]]: зависимость меняется, если изменилось время последней модификации файла.
229 230
- [[yii\caching\TagDependency]]: Связывает кэшированные данные элемента с одним или несколькими тегами. Вы можете
  аннулировать кэширование данных элементов с заданным тегом(тегами) по вызову. [[yii\caching\TagDependency::invalidate()]].
Nepster committed
231 232


233
## Кэширование запросов <span id="query-caching"></span>
Nepster committed
234

235 236
Кэширование запросов - это специальная функция кэширования, построеная на основе кэширования данных.
Она предназначена для кэширования результатов запросов к базе данных.
Nepster committed
237

238
Кэширование запросов требует [[yii\db\Connection|DB connection]] и приложения действительный `cache`. Простое использование
Nepster committed
239 240 241 242 243
запросов кэширования происходит следующим образом, предпологая что `$db` это экземпляр [[yii\db\Connection]]:

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

244 245
    // Результат SQL запроса будет возвращен из кэша если
    // кэширование запросов включено и результат запроса присутствует в кэше
Nepster committed
246 247 248 249 250
    return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();

});
```

251
Кэширование запросов может быть использованно как для [DAO](db-dao.md), так и для [ActiveRecord](db-active-record.md).
Nepster committed
252

253 254 255
> Информация: Некоторые СУБД (например, [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html)) поддерживают
  кэширование запросов на стороне сервера БД. Вы можете использовать любой механизм кэширования запросов. Кэширование 
  запросов описанное выше, имеет преимущество, поскольку можно указать гибкие зависимости кэша и это более эффективно.
Nepster committed
256 257


258
### Конфигурации <span id="query-caching-configs"></span>
Nepster committed
259 260 261

Кэширование запросов имеет три глобальных конфигурационных параметра через [[yii\db\Connection]]:

Nepster committed
262
* [[yii\db\Connection::enableQueryCache|enableQueryCache]]: включить или выключить кэширование запросов.
263 264 265 266 267 268 269
  По умолчанию `true`. Стоит отметить, что для использования кэширования вам может понадобиться компонент
  cache, как показано в [[yii\db\Connection::queryCache|queryCache]].
* [[yii\db\Connection::queryCacheDuration|queryCacheDuration]]: количество секунд, в течение которых результат кэшируется.
  Для бесконечного кэша используйте `0`. Именно это значение выставляется [[yii\db\Connection::cache()]] если не указать
  время явно.
* [[yii\db\Connection::queryCache|queryCache]]: ID компонента кэширования. По умолчанию `'cache'`. Кэширования запросов
  работает только если используется компонент приложения кэш.
Nepster committed
270 271


272
### Использование <span id="query-caching-usages"></span>
Nepster committed
273

274 275
Вы можете использовать [[yii\db\Connection::cache()]], если у вас есть несколько SQL запросов, которые необходимо
закэшировать:
Nepster committed
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

```php
$duration = 60;     // кэширование результата на 60 секунд
$dependency = ...;  // параметры зависимости

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

    // ... выполнять SQL запросы здесь ...

    return $result;

}, $duration, $dependency);
```

Любые SQL запросы в анонимной функции будут кэшироваться в течении указанного промежутка времени с заданной зависимостью.
291 292
Если результат в кэше актуален, запрос будет пропущен и, вместо этого, из кэша будет возвращен результат. Если вы не
укажете `'$duration'`, значение [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] будет использоваться вместо него.
Nepster committed
293

294 295
Иногда в пределах `"cache()"` вы можете отключить кэширование запроса. В этом случае вы можете использовать
[[yii\db\Connection::noCache()]].
Nepster committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

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

    // SQL запросы, которые используют кэширование

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

        // SQL запросы, которые не используют кэширование

    });

    // ...

    return $result;
});
```

314 315
Если вы просто хотите использовать кэширование для одного запроса, вы можете вызвать [[yii\db\Command::cache()]] при
построении конманды. Например:
Nepster committed
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

```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;
});
```


339
### Ограничения <span id="query-caching-limitations"></span>
Nepster committed
340

341 342
Кэширование запросов не работает с результатами запросов, которые содержат обработчики ресурсов. Например, при использовании
типа столбца `BLOB` в некоторых СУБД, в качестве результата запроса будет выведен ресурс обработчик данных столбца.
Nepster committed
343

344 345
Некоторые кэш хранилища имеют ограничение в размере данных. Например, Memcache ограничивает максимальный размер каждой
записи до 1 Мб. Таким образом, если результат запроса превышает этот предел, данные не будут закэшированны.