Да, это опять некие костыли (как и в первой моей статье), но мне кажется, что эти (учитывая победное шествие PostgreSQL) могут и пригодится даже большему числу людей.
Все кто работают с PGPool в режиме Master-Slave рано или поздно столкнутся с задачей, когда делать селекты надо непременно из мастера. Благо разработчики о нас позаботились и дали такую возможность. Кто видел схему работы PGPool меня поймут: пишем перед селектом нехитрую строчку /*NO LOAD BALANCE*/ и наш запрос PGpool отправит в мастер базу.
Проблемы начинаются тогда, когда нам нужно использовать ORM.
На примере Yii2 мы пока решили это так:
Переопределяем класс ActiveQuery и, главное, его метод createCommand()
class ActiveQuery extends \yii\db\ActiveQuery {
private $_noLoadBalance = false;
/**
* Не отправлять запрос на балансировщик, а прямо в мастер
*
* @return $this
*/
public function noBalance() {
$this->_noLoadBalance = true;
return $this;
}
/**
* @inheritdoc
*/
public function createCommand($db = null)
{
/* @var $modelClass ActiveRecord */
$modelClass = $this->modelClass;
if ($db === null) {
$db = $modelClass::getDb();
}
if ($this->sql === null) {
list ($sql, $params) = $db->getQueryBuilder()->build($this);
} else {
$sql = $this->sql;
$params = $this->params;
}
$comment = '';
if (true === $this->_noLoadBalance) {
$comment = '/*NO LOAD BALANCE*/';
}
return $db->createCommand($comment . $sql, $params);
}
}
А используем мы это так:
$user = User::find()->where([
User::ATTR_ID => $userid,
])
->noBalance()
->one();
И, очень хочется, чтобы разработчики Yii все-таки как-то это сделали «внутри» из коробки.
Комментарии (15)
bohdan4ik
06.08.2016 23:18+2> User::find()->where([User::ATTR_ID => $userid,])
В Yii2 можно юзать ActiveRecord::primaryKey()
https://github.com/yiisoft/yii2/blob/master/framework/db/ActiveRecord.php#L318vladnevlad
06.08.2016 23:31-4простите… вы о чем? User::find()->where([User::ATTR_АБЫРВЛАГ=> $userАбырвлаг,])
просто я не заметил, где я в своем посте предложил соревноваться в знании фрейморка.bohdan4ik
06.08.2016 23:38+1Вы излишне агрессивны.
Вы поделились кусочком совего знания (предложили посоревноваться в знании PG, ага), я поделился кусочком своих знаний.
Имелось ввиду, что можно использовать существующую функциональность и не вносить дублирование кода.
> User::find()->where([User::primaryKey() => $userid])
Подсветки, ессесн, нет, спасибо НЛО.
Аривидерчи, Влад.
vladnevlad
06.08.2016 23:39-6но я вам все-таки отвечу почему не PK. Дело в том, что в IDE есть такая штука как Find Usage. Дальше можете подумать сами.
renskiy
07.08.2016 08:04+1А в каких случаях может возникнуть ситуация, когда запрос надо направить именно в мастер?
vladnevlad
07.08.2016 08:40например, когда вы сделали INSERT и вам сразу же надо узнать состояние таблицы т.к. у вас нет гарантии, что INSERT сделали только вы. Это, конечно, абстрактно.
vladnevlad
07.08.2016 08:49+1ну, или пример из практики:
Приходит звонок в коллцентр, записывается запись в мастер и ставится в кеш ключ, что для такого-то оператора есть звонок c некоторым ID.
У оператора в рабочем месте AJAX постоянно опрашивает сервер, есть ли для него звонки? Когда он получает ключ, что звонок есть, он пытается подгрузить карточку этого звонка, делая SELECT. У PGPool очень небольшой лаг синхронизации, но иногда возникает ситуация, что ID того звонка, который закоммитился в мастер еще нет в SLAVE базе.
Таких примеров можно привести много.renskiy
07.08.2016 12:13Не проще ли в этом случае в кэш записывать не только ID звонка, но все данные о звонке сразу? В этом случае клиент не будет делать два запроса в случае если новый звонок появился, да и SELECT в мастер не понадобится по идее. Плюс, не нужно будет делать кэш персистентным (иначе придется что-то думать на случай потери кэша).
vladnevlad
07.08.2016 13:21Я вам описал частный случай, который, конечно, не совершенен и просто показывает общую картину. Мы эту реализацию в рамках данного поста лучше не будем обсуждать — у меня есть пара мыслей о статьях на тему Asterisk + Yii2.
Если хотите, я приведу примеры не из моих модулей, где это критично, но завтра.
FractalizeR
08.08.2016 14:42+1И, очень хочется, чтобы разработчики Yii все-таки как-то это сделали «внутри» из коробки.
Что именно? Полную поддержку PGPool в ActiveRecord, который должен прозрачно работать не только с Postgres но и со многими другими БД?
Мне кажется, таких вещей, как
noBalance()
, который работает только для Postgres и только для PGPool в ActiveRecord во фреймворках лучше не реализовывать вообще.
atc
Статья о том, что в php есть наследование?
vladnevlad
Разработчики Yii изменят реализацию класса и все пойдет прахом. Это костыль.
VolCh
Для разработчиков Yii публичный контракт ничего не значит?
SamDark
Значит.
ErickSkrauch
Это не костыль. Это проектное решени. Это нормально.