【问题标题】:Symfony/Propel 1.4: Read from one, write to other DBSymfony/Propel 1.4:从一个数据库读取,写入另一个数据库
【发布时间】:2012-10-25 09:41:44
【问题描述】:

我们在 Symfony 1.4/Propel 1.4 中有一个现有项目(SNS 网站+android/Iphone 游戏)

我们在 DB 服务器(比如 DB1)上遇到了额外的负载。我们正在做 DB 优化,但作为直接的解决方案,我们决定再创建一个 DB 服务器,因为 DB2 始终是 DB1 的精确副本。目前我们只有 DB1,用于读写操作。

现在我们需要将所有读取操作移至 DB2,并保持 DB1 上的写入操作(通常在事务中)与现在一样。

进行这些更改的可能方法是什么(在没有太多停机时间的生产服务器上),如果可能的话,只需最少的代码更改。

在第一条评论后编辑

根据 J0k 提供的链接和其他一些链接,我已经在本地开发环境中完成了以下操作。

  1. 创建了一个测试 symfony 1.4 项目
  2. 更新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 条目分别为 WON1WON

  3. 运行 symfony 任务

    php symfony propel:build-schema
    php symfony propel:build-model
    php symfony cc
    
  4. 创建了一个模块并添加了以下代码:

    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 //正确的预期输出

    on Read connection, result=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 是空的?

我也尝试按照old forums 中的定义编辑 sfDatabaseConfigHandler.class.php,但这样做会在某处破坏 symfony,并且不会在 Web 甚至日志中显示任何内容。

【问题讨论】:

  • 你检查过the doc吗?
  • 嗨@j0k,我浏览了那个 URL,但不知道如何在 symfony 中使用该信息。我根据不同链接提供的示例,使用我正在尝试的代码/配置编辑了问题。你能告诉我我在哪里做错了吗?
  • 嗨@j0k,似乎没有什么对我有用。这迫使我使用核心框架文件来解决生产服务器上的紧急问题。我发布了我的解决方案。我知道这不是一个好习惯,但请你看看它并想提出一些建议。
  • 这太疯狂了,文档中的官方信息不起作用?您是否也尝试过推进 1.6(在本地)?顺便说一句,您在回答中描述的是我也在网上找到的一个黑客解决方案,但它是针对旧的推进版本(我认为是 1.2)。
  • 是的@j0k 它的(官方信息..)是极不可能的,我同意我一定犯了一些错误,但最终结果是:它对我不起作用。后来我恢复到推进 1.4,但该解决方案首先在 1.6 上进行了测试,并且也在 1.6 上工作。我从有问题的链接中得到了想法,但它是针对 Propel 1.2 的。关于黑客攻击,是的,它真正的黑客攻击&我提到我不推荐我的一般情况下的解决方案,但我的情况不同。生产服务器停机,堆栈持有者站在我身后寻求解决方案,在这种情况下黑客攻击是可以接受的,不是吗?现在正在寻找完美的解决方案。

标签: php symfony1 symfony-1.4 propel


【解决方案1】:

我确定我犯了一些错误,但是无论在 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;

到(之前加了一行)

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');
  }
}

我仍然不建议编辑核心文件,但这个解决方案在紧急情况下对我们有用。如果需要,其他人可以在紧急情况下使用它。仍在寻找完美的解决方案。

【讨论】:

    【解决方案2】:

    您应该根据to the doc(在 github 上)为slaves 加上一个connection 条目添加一个新级别

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-06
      相关资源
      最近更新 更多