Страница 1 из 1

[РЕШЕНО] Использую 2 компонента DBConnection

Добавлено: 2012.09.26, 18:41
DropSQL
Здравствуйте, подскажите плз, можно ли как-то в профайлинге узнать какой конкретно компонент использовался при выполнении запроса?

Сделал таким путем, возможно не правильно, подскажите как исправить:

Код: Выделить всё

public static function master()
    {
        self::setDbConnection(Yii::app()->db);
        return self::model();
    }

    public static function slave()
    {
        self::setDbConnection(Yii::app()->slave);
        $model = self::model();
        return $model;
    }

    public static function setDbConnection($dbConnection)
    {
        self::$_db = $dbConnection;
    }

    public function getDbConnection()
    {
        if(self::$_db === null){
            $db = parent::getDbConnection();
        }else{
            $db = self::$_db;
        }
        return $db;
    }
Заранее благодарен!

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 11:59
samdark
Лучше два компонента сделать.

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 12:04
DropSQL

Код: Выделить всё

Yii::app()->slave
Yii::app()->db
Это же 2 компонента, не так ли? или я чего-то не так понимаю?

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 12:05
anton44eg
да. потом в модели можно переопределить метод getDbConnection() и модели будут к нужной БД идти, ну а для DAO Yii::app()->slave->createCommand() и Yii::app()->db->createCommand()

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 12:11
DropSQL
Вы не поняли фишку, мне нужно чтобы все селекты шли на slave, а инсерты и апдейты, делеты на master.
Я сначала сделал onBeforeFind - и тупо менял БД, мне эта идея до сих пор нравится, но конструкция

Код: Выделить всё

Model::model()->cache(1)->findAll();
не работает в таком случае, потому что cache отрабатывает раньше чем onBeforeFind :( Пришлось сделать такой вид:

Код: Выделить всё

Model::master()->cache(1)->findAll();
Model::slave()->cache(1)->findAll();

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 12:13
DropSQL
Если Знаете как решить подскажите плз (аналог onBeforeFind, чтобы автоматом определяло), буду очень благодарен.
И вопрос стоял в том как узнать с какого компонента идет запрос в профилировании?

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 12:40
samdark
А зачем что-то менять, если используется кеш?

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 12:53
DropSQL
хорошо, ты прав :) тогда возникает вопрос :) а как можно узнать использую я кэширование или нет?

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 13:19
samdark
$this->dbConnection->queryCachingCount>0

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 13:35
Denyii
DropSQL писал(а):Вы не поняли фишку, мне нужно чтобы все селекты шли на slave, а инсерты и апдейты, делеты на master......
Не давно на форуме видел ссылку на это расширение http://www.yiiframework.com/extension/d ... splitting/
Тут:viewtopic.php?f=3&t=8533 (Master - slave репликация + Yii)

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 14:22
DropSQL
супер решение! :) спасибо большое, сейчас только проверю как оно работает с кэшированием, по коду проблема должна остаться

Re: Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 14:48
DropSQL
решил вроде:

Код: Выделить всё

    public function getSlave() {
        if (!isset($this->_slave)) {
            foreach ($this->slaves as $slaveConfig) {
                if (!isset($slaveConfig['class']))
                    $slaveConfig['class']='CDbConnection';
                try {
                    if ($slave=Yii::createComponent($slaveConfig)) {
                        Yii::app()->setComponent('dbslave',$slave);
                        $this->_slave=$slave;
                        break;
                    }
                } catch (Exception $e) {
                    Yii::log('Create slave database connection failed!','warn');
                    continue;
                }
            }
            if (!$this->_slave) {
                $this->_slave=clone $this;
                $this->_slave->enableSlave=false;
            }
        }
        return $this->_slave;
    }
этот метод заменить на:

Код: Выделить всё

    public function getSlave() {
        if (!isset($this->_slave)) {
            shuffle($this->slaves);
            foreach ($this->slaves as $slaveConfig) {
                if (!isset($slaveConfig['class']))
                    $slaveConfig['class']='CDbConnection';
                try {
                    if ($slave=Yii::createComponent($slaveConfig)) {
                        Yii::app()->setComponent('dbslave',$slave);
                        $this->_slave=$slave;
                        break;
                    }
                } catch (Exception $e) {
                    Yii::log('Create slave database connection failed!','warn');
                    continue;
                }
            }
            if (!$this->_slave) {
                $this->_slave=clone $this;
                $this->_slave->enableSlave=false;
            }
        }
        $this->_slave->cache($this->queryCachingDuration, $this->queryCachingDependency, $this->queryCachingCount);
        $this->cache(0);
        return $this->_slave;
    }

Re: [РЕШЕНО] Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 14:59
DropSQL
Проверил, работает кеширование хорошо.

Re: [РЕШЕНО] Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 15:55
grigori
к сожалению, расширение dbreadwritesplitting имеет 2 недостатка:

Код: Выделить всё

self::isReadOperation($sql)
...
 public function isReadOperation($sql) {
   return preg_match('/^\s*(SELECT|SHOW|DESCRIBE|PRAGMA)/i',$sql);
 
1. статический метод должен быть статическим, иначе будут сообщения об ошибке
2. прогонять каждый запрос к базе через preg_match - неэффективно

в общем, это решение на коленке, лучше уж костыль

Код: Выделить всё

class SotmActiveRecord extends  CActiveRecord
{
    private $writeDb;
    private $readDb;
    /**
     * Set the replication switch to use master
     * @return bool
     */
    public function beforeSave()
    {
        self::$db = $this ->writeDb ?: ($this->writeDb = Yii::app()->writeDb);
        return parent::beforeSave();
    }

    /**
     * Set to db to  slave
     * @retur bool
     */
    public function afterSave()
    {
        self::$db = $this ->readDb ?: ($this->readDb = Yii::app()->getDb());
        return parent::afterSave();
    }

    /**
     * Set to db to master
     * @retur bool
     */
    public function beforeDelete()
    {
        self::$db = $this ->writeDb ?: ($this->writeDb = Yii::app()->writeDb);
        return parent::beforeDelete();
    }

    /**
     * Set to db to slave
     * @retur bool
     */
    public function afterDelete()
    {
        self::$db = $this ->readDb ?: ($this->readDb = Yii::app()->getDb());
        return parent::afterDelete();
    }
}
...
class Customers extends SotmActiveRecord {
 

Re: [РЕШЕНО] Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 15:59
lancecoder
1 ар+дао(если в нужном месте)
2 ар

Re: [РЕШЕНО] Использую 2 компонента DBConnection

Добавлено: 2012.09.27, 17:44
DropSQL
прегматч можно заменить на сторковую функцию вроде strpos, если это так критично.
Работает прекрасно включая кеширования.
Если бы вы читали выше - поняли бы почему этот костыль меня не устроил, там проблемы как минимум с кэшированием.

Меня реализация этого модуля очень порадовала, я уверен что больших тормозов эта строковая функция не создаст, относительно остальных тормозов фреймворка.