Кеширование в Yii с помощью тегов

Yii позволяет кешировать данные в виде массива возвращаемые прямиком из базы данных.
А у системы кеширования есть разные зависимости. Вот только ни одна из этих зависимостей не позволяет автоматически отслеживать изменения в таблице без обращения к ней же (имею ввиду CDbCacheDependency), что в нагруженных системах бессмысленно.

Для подобных вещей придумали так называемое тегирование. Т.е. создается какой-то тег, который сохраняется со всеми кешами связанными с данной таблицей. И как только он меняется, все связанные кеши должны перезагрузиться. Как оказалось в Yii это делается очень просто.



Стоит упомянуть, что для большего комфорта используется Active Record.

Делается это так. Создаем новую зависимость и сохраняем ее, к примеру в components:

/**
 * CTagCacheDependency class.
 * 
 * CTagCacheDependency represents a dependency based on a autoincrement(timestamp) of tags
 *
 * @author Roman <astronin@gmail.com>
 * @since 1.0
 */
class CTagCacheDependency extends CCacheDependency
{
    /**
     * @var autoincrement(timestamp) param is used to
     * check if the dependency has been changed.
     */
    public $tag;
    /**
     * Cache component, by default used - cache
     * @var CCache
     */
    public $cache;
    /**
    * Name of cache component, by default used - cache
    * @var string
    */
    public $cacheName;

    /**
     * Constructor.
     * @param string $tag value of the tag for module
     */
    public function __construct($tag=null, $cacheName='cache')
    {
        $this->tag=$tag;
        $this->cacheName = $cacheName;
    }
        
    /**
     * Generates the data needed to determine if dependency has been changed.
     * This method returns the integer(timestamp).
     * @return mixed the data needed to determine if dependency has been changed.
     */
    protected function generateDependentData()
    {
        if($this->tag!==null)
                {
                        $this->cache = Yii::app()->getComponent($this->cacheName);
                        $t = $this->cache->get($this->tag);
                        if ($t === false) {
                                $t = microtime(true);
                                $this->cache->set($this->tag, $t);
                        }
                        return $t;
                }
    }
}



В модели указываем, когда мы будем использовать новую зависимость. Поскольку мы хотим это сделать для всей модели добавляем код в функцию beforeFind:

protected function beforeFind() {
        $this->cache(30, new CTagCacheDependency(get_class($this)));
        parent::beforeFind();
}


Ну или где хотим, главное тут — "$this->cache(30, new CTagCacheDependency(get_class($this)));"

  • 30 — время хранения кеша, но лучше вынести это значение в переменную
  • CTagCacheDependency — класс нашей новой зависимости
  • get_class($this) — имя тега — имя модели


В качестве тега у нас выступает просто название класса, модели, связанной с определенной таблицей.

Ну и когда мы удаляем или сохраняем что-то, пишем в нужных местах(в функциях afterDelete, afterSave):

Yii::app()->cache->set(get_class($this), microtime(true), 0);


  • 0 — бесконечное хранение
  • get_class($this) — имя тега — имя модели
  • microtime(true) — новое значение тега


Этим самым мы обновляем тег связанный с данной моделью, а соответственно и с таблицей. Теперь, когда тег обновится в следствии обновления таблицы, все кеши с зависимостью от этого тега должны будут обновиться.

Используется кеш по-умолчанию — компонент: cache. Но можно указать другой свой.

Используемая литература:


UPD Важный!

Обновил код класса CTagCacheDependency

Теперь конструктор принимает имя Компонента как строку. Например:
$this->cache($duration, new CTagCacheDependency(get_class($this), 'cache'));


Сделано из-за некорректной работы с memcache.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 5

    0
    Ещё вот такое решение было korzh.net/2011-04-tegirovanie-kesha-v-yii-framework-eto-ne-bolno.html
      0
      Еще у меня в серлине было что-то похожее, я те показывал. Но там не совсем теггирование.
      +1
      Спасибо за статью!
      Было бы полезно иметь готовую обертку, которой можно было бы указать: кешируй такие-то модели, чтобы не прописывать beforeFind, afterSave и т.д.
        0
        Хотелось бы что нибудь типа
        Yii::app()->cache->set($key, $value, $time, $var);
        какой нибудь CVarCacheDependency
          0
          Спасибо за идею.

          Only users with full accounts can post comments. Log in, please.