我们在 Symfony 1.4/Propel 1.4 中有一个现有项目(SNS 网站+android/Iphone 游戏)
我们在 DB 服务器(比如 DB1)上遇到了额外的负载。我们正在做数据库优化,但作为直接的解决方案,我们决定再创建一个数据库服务器,就像 DB2 一直是 DB1 的精确副本一样。目前我们只有 DB1,用于读写操作。
现在我们需要将所有读操作移到 DB2 并保持 DB1 上的写操作(通常在事务中)像现在一样。
进行这些更改的可能方法是什么(在没有太多停机时间的生产服务器上),如果可能,代码更改最少。
在第一条评论后编辑
基于 J0k 给出的链接和其他一些链接,我在本地开发环境中做了以下工作。
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
。 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
,输出是,我想在创建读/写连接时传递
OddPlayPeer::DATABASE_NAME
是问题所在,但在线示例中是如何建议的。有人可以建议我在哪里犯错吗?编辑:输入更多
我更新了
lib\vendor\symfony\lib\plugins\sfPropelPlugin\lib\vendor\propel\Propel.php
中的调试 echo 以检查它是如何返回连接的。发现它在下面输入 if (line 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 是空的?我还尝试编辑 old forums 中定义的 sfDatabaseConfigHandler.class.php,但这样做会在某处破坏 symfony 并且没有任何内容显示在网络上,甚至在日志中。
最佳答案
我确定我犯了一些错误,但是无论 Propel/symfony 的官方文档中提出的建议,甚至在 stackoverflow 上的建议,似乎都不适合我。可能官方文档应该更好地照顾那些没有很多 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;
with(中间加了一行)
// 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,因为生产升级需要经过很好的测试。)
文件:plugins/sfPropelORMPlugin/lib/vendor/propel/runtime/lib/Propel.php
更改了第 601 行
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
to(之前加了一行)
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');
}
}
我仍然不建议编辑核心文件,但该解决方案在紧急情况下对我们有用。如果需要,其他人可以在 紧急情况下使用它 。仍在寻找完美的解决方案。
关于php - Symfony/Propel 1.4 : Read from one, 写入其他数据库,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13234058/