Пример кэширования моделей

03.06.2013

Пример кэширования в yiiНа многих сайтах есть листинги моделей, которые берутся из базы данных по определенным условиям.

К примеру, в одном из проектов который я делал, было 3 категории заведений - гостиницы, квартиры и частные дома. Все записи хранились в одной таблице place, но type_id были разные. На сайте есть страницы с полными листингами по этим категориям, их-то нам и нужно закэшировать.

01. Подключим CDbCache

Для примера будем использовать CDbCache, хотя никто не запрещает тоже самое сделать и с memcached, это уже на Ваше усмотрение.

Как следует из названия CDbCache хранит данные в таблицы БД, по умолчанию она называется YiiCache, но Вы можете поменять название на любое, определив в конфиге параметр "cacheTableName". Таблица содержит хэш названия кэшированных данных, время окончания достоверности данных и сами сериализованные данные. Вот сам конфиг:

'components' => array(
    'cache' => array(
        'class' => 'CDbCache',
        'connectionID' => 'db',
    ),
    'db' => array(
        '........'
        'schemaCachingDuration' => 10800
    ),
),

Если не указать connectionId, кэш будет храниться в SQLlite3 в каталоге runtime.

02. Настроим саму модель для кэширования

После удачного получения кэша и попытке работать с этим кэшем как с обычными моделями я столкнулся с тем, что ансериализованные модели не видят подключенных поведений(behaviors). Решается импортом классов поведений перед классом модели, а дальше уже обращаемся к классам не через алиасы, а напрямую к классу:

Yii::import('ext.withRelated.WithRelatedBehavior');
Yii::import('zii.behaviors.CTimestampBehavior');
class Place extends CActiveRecord {
    ........
    public function behaviors() {
        return array(
            'CTimestampBehavior' => array(
                'class' => 'CTimestampBehavior',
                'createAttribute' => 'created_date',
                'updateAttribute' => 'updated_date',
            ),
            'withRelated' => array(
                'class' => 'WithRelatedBehavior',
            ),
        );
    }
    ........
}

03. Кэшируем модели

У нас есть отдельный экшен, в которым и происходит выборка необходимых моделей. Экшен вынесен в отдельный класс, потому что для разных типов заведений - разные УРЛы, и соответственно контроллеры:

class ListAction extends CAction {
    public function run() {
        $typeId = 0;

        if($this->getController()->id == 'hotel') {
            $typeId = Place::TYPE_HOTEL;
            $cacheId = 'hotelCache';
        } elseif($this->getController()->id == 'kvartira') {
            $typeId = Place::TYPE_KVARTIRA;
            $cacheId = 'kvartiraCache';
        } elseif($this->getController()->id == 'cottage') {
            $typeId = Place::TYPE_COTTAGE;
            $cacheId = 'cottageCache';
        }

        $models = Yii::app()->cache->get($cacheId);

        if($models === false) {
            $criteria = new CDbCriteria();
            $criteria->addCondition('type_id = '.$typeId);
            $models = Place::model()->active()->findAll($criteria);

            Yii::app()->cache->set($cacheId, $models, 10800);
        }

        $this->getController()->render('/common/list', array('models' => $models));
    }
}

Yii::app()->cache->get($cacheId) - возвращает ансериализованный массив моделей, если нет - Yii::app()->cache->set($cacheId, $models, 10800), устанавливаем кэш по-новой.

Вот и всё, как видно простое кэширование не так сложно. Кстати, делал замеры с помощью Apache Benchmark производительность выросла ровно в 2 раза.

ab -n 100 -c 5 http://moysait.loc

И ещё мелочь - очищается кэш командой Yii::app()->cache->flush().

P.S.: В комментариях Андей правильно заметил, что вместо CDBCache::set() можно использовать кэширование AR. Разница не сильно большая, но в моем случае мы кэшируем данные, а в случает Андея получается кэширование запроса к БД. Что лучше - я не знаю, но суть одна.

blog comments powered by Disqus
Наверх