Symfony/Propel 1.4: чтение из одной, запись в другую БД
У нас есть существующий проект (сайт SNS + игры для Android/Iphone) в Symfony 1.4/ Propel 1.4
Мы испытываем дополнительную нагрузку на сервер БД (скажем, DB1). Мы занимаемся оптимизацией БД, но в качестве немедленного решения мы решили создать еще один сервер БД, чтобы DB2 всегда была точной копией DB1. В настоящее время у нас есть только DB1, используемый для операций чтения и записи.
Теперь нам нужно перенести все операции чтения в DB2 и сохранить операции записи (обычно в транзакциях) в DB1, как сейчас.
Каковы возможные способы внесения этих изменений (на рабочем сервере без больших простоев) и, если возможно, с минимальными изменениями кода.
Изменить после первого комментария
Основываясь на ссылке, предоставленной J0k, и некоторых других ссылках, я сделал следующее в локальной среде разработчика.
- Создан тестовый проект Symfony 1.4
Обновлен database.yml следующим образом
all: propel: class: sfPropelDatabase param: classname: PropelPDO dsn: 'mysql:host=localhost;dbname=wzo;' username: root password: mysql encoding: utf8 persistent: true pooling: true slaves: slave1: dsn: 'mysql:host=localhost;dbname=wzoslv;' username: root password: mysql encoding: utf8
Где база данных
wzoslv
точная копия базы данныхwzo
кроме изменений в одной тестовой записи. На столеodd_play
строка 26 (PK) столбецresult
записиWON1
а такжеWON
соответственно.запускать задачи Symfony
php symfony propel:build-schema php symfony propel:build-model php symfony cc
Создал модуль и добавил следующий код:
class wzoActions extends sfActions { public function executeIndex(sfWebRequest $request) { $con_write = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_WRITE); $con_read = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_READ); $oddPlay = OddPlayPeer::retrieveByPK(26,0,$con_write); echo "on write connection, result=".$oddPlay->getResult(); $oddPlayRead = OddPlayPeer::retrieveByPK(26,0,$con_read); echo "<br/>on Read connection, result=".$oddPlayRead->getResult(); exit; $this->setLayout('layout'); } }
Бежать
http://local.sftest.com/index.php/wzo/index
в браузере вывод был,при записи соединения, result=WON // Исправить ожидаемый результат
при подключении для чтения, результат = WON // Неправильно. Это должно быть WON1
Я думаю прохождение OddPlayPeer::DATABASE_NAME
Хотя создание соединения для чтения / записи является проблемой, но именно так, как это было предложено в онлайн-примерах. Может кто-нибудь подсказать, где я ошибаюсь?
Изменить: немного больше ввода
Я обновил отладочный эхо в lib\vendor\symfony\lib\plugins\sfPropelPlugin\lib\vendor\propel\Propel.php
чтобы проверить, как он возвращает соединение. Обнаружил, что ввод в следующем if (строка 544-549)
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
if (empty($slaveconfigs)) {
echo "inelseifif<br/>";// no slaves configured for this datasource
self::$connectionMap[$name]['slave'] = false;
return self::getConnection($name, Propel::CONNECTION_WRITE); // Recurse to get the WRITE connection
}
где $slaveconfigs
пустые, поэтому возвращаем соединение для записи. Теперь вопрос, почему slaveconfigs пуст?
Я также пытаюсь отредактировать sfDatabaseConfigHandler.class.php, как это было определено на старых форумах, но, делая это, где-то ломаю symfony и ничего не отображается в сети и даже в журналах.
2 ответа
Я уверен, что делаю какую-то ошибку, но все, что предлагается в официальных документах Propel / symfony и даже здесь, в stackru, кажется, не работает для меня. Вероятно, официальные документы должны лучше заботиться о программистах, которые не имеют большого опыта Symfony.
Хотя мы не предпочитаем редактировать основные файлы каких-либо фреймворков / сторонних библиотек, но это заставляет меня редактировать основные файлы, чтобы сделать рабочее решение для меня. Решение, которое сработало для меня, заключается в следующем:
database.yml Мой файл database.yml выглядит следующим образом:
all:
propel:
class: sfPropelDatabase
param:
classname: PropelPDO
dsn: 'mysql:host=localhost;dbname=wzo;'
username: testuserwzo
password:
encoding: utf8
persistent: true
pooling: true
slave:
class: sfPropelDatabase
param:
classname: PropelPDO
dsn: 'mysql:host=localhost;dbname=wzoslv;'
username: testuserwzoslv
password:
encoding: utf8
persistent: true
pooling: true
После этого я отредактировал файл Propel.php следующим образом
Для Propel 1.4
Файл: lib/vendor/ symfony / lib / plugins / sfPropelPlugin / lib/vendor/ propel / Propel.php
Смена строки 542-543
// we've already ensured that the configuration exists, in previous if-statement
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
с (добавлено одна строка между)
// we've already ensured that the configuration exists, in previous if-statement
self::$configuration['datasources'][$name]['slaves'] = isset(self::$configuration['datasources']['slave']) ? self::$configuration['datasources']['slave'] : null;
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
Затем в том же файле изменили строку 560
$con = Propel::initConnection($conparams, $name);
в
$con = Propel::initConnection($conparams, 'slave'); //I know its bad practive to put hard-coded value but at that moment, I was more interested in working solution without caring about best practices.
Для propel 1.6 (мы обновили propel только для того, чтобы это работало, но позже вернулись к propel 1.4, так как обновление на производстве должно быть хорошо протестировано.)
Файл: плагины /sfPropelORMPlugin/lib/vendor/propel/runtime/lib/Propel.php
Изменена линия 601
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
в (добавлена одна строка раньше)
self::$configuration['datasources'][$name]['slaves'] = isset(self::$configuration['datasources']['slave']) ? self::$configuration['datasources']['slave'] : null;
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
Затем в том же файле изменили строку 629
$con = Propel::initConnection($conparams, $name);
в
$con = Propel::initConnection($conparams, 'slave');
Затем следующий тестовый файл дал ожидаемый результат
class kapsActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
$con_write = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_WRITE);
$con_read = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_READ);
$oddPlay = OddPlayPeer::retrieveByPK(28,0,$con_write);
echo "on write connection, result=".$oddPlay->getResult().$oddPlay->getPlayscore();
$oddPlayRead = OddPlayPeer::retrieveByPK(27,0,$con_read);
echo "<br/>on Read connection, result=".$oddPlayRead->getResult().$oddPlayRead->getPlayscore();
exit;
//$this->setLayout('layout');
}
}
Я до сих пор не рекомендую редактировать основные файлы, но это решение работало для нас как в аварийном состоянии. Кто-то другой, при необходимости, может использовать его в аварийном состоянии. Все еще ищем идеальное решение.
Вы должны добавить новый уровень slaves
плюс connection
запись, согласно документу (на github)
all:
propel:
class: sfPropelDatabase
param:
classname: PropelPDO
dsn: 'mysql:host=localhost;dbname=wzo;'
username: root
password: mysql
encoding: utf8
persistent: true
pooling: true
slaves:
connection:
slave1:
dsn: 'mysql:host=localhost;dbname=wzoslv;'
username: root
password: mysql
encoding: utf8