2013-11-04 128 views
3

我正在从一个Yii安装中运行多个网站的项目。每个网站都有自己的数据库,所以数据库连接必须是动态的。动态更改数据库连接Yii

我做了什么,我创建了一个BeginRequestBehavior,它将启动'onBeginRequest'。在这里,我将检查哪个URL已被调用,并确定匹配的数据库(不在我的代码中)并创建(或覆盖)'db'组件。

<?php 
class BeginRequestBehavior extends CBehavior 
{ 

    /** 
    * Attaches the behavior object to the component. 
    * @param CComponent the component that this behavior is to be attached to 
    * @return void 
    */ 

    public function attach($owner) 
    { 

     $owner->attachEventHandler('onBeginRequest', array($this, 'switchDatabase')); 

    } 

    /** 
    * Change database based on current url, each website has his own database. 
    * Config component 'db' is overwritten with this value 
    * @param $event event that is called 
    * @return void 
    */ 

    public function switchDatabase($event) 
    { 
     // Here some logic to check which url has been called.. 

     $db = Yii::createComponent(array(
      'class' => 'CDbConnection', 
      'connectionString' => 'mysql:host=localhost;dbname=test', 
      'emulatePrepare' => true, 
      'username' => 'secret', 
      'password' => 'verysecret', 
      'charset' => 'utf8', 
      'enableProfiling' => true, 
      'enableParamLogging' => true 
     )); 

     Yii::app()->setComponent('db', $db); 

    } 
} 

它工作正常,但这是正确的方法?在其他方法中,我看到人们为他们的模型创建自己的'MyActiveRecord'(扩展CActiveRecord)并将db组件放入属性中。他们为什么这样做?恐怕数据库连接会以这种方式超出必要的次数。

回答

4

我用一个模型功能定义了数据库连接:

public static $conection; // Model attribute 

public function getDbConnection(){ 

    if(self::$conection!==null) 
     return self::$conection; 

    else{ 
     self::$conection = Yii::app()->db2; // main.php - DB config name 

     if(self::$conection instanceof CDbConnection){ 
      self::$conection->setActive(true); 
      return self::$conection; 
     } 
     else 
      throw new CDbException(Yii::t('yii',"Active Record requires a '$conection' CDbConnection application component.")); 
    } 
} 

main.php

'db'=>array( 
    'connectionString' => 'mysql:host=192.168.1.*;dbname=database1', 
    'emulatePrepare' => true, 
    'username' => 'root', 
    'password' => 'password', 
    'charset' => 'utf8', 
    'enableProfiling'=>true, 
    'enableParamLogging' => true, 
), 
'db2'=>array(
    'class'=>'CDbConnection', 
    'connectionString' => 'mysql:host=192.168.1.*;dbname=database2', 
    'emulatePrepare' => true, 
    'username' => 'root', 
    'password' => 'password', 
    'charset' => 'utf8', 
), 
+0

我不需要多个数据库,只有一个,它的变化取决于在你的网址上。你把db组件放在$ conection属性中的原因是什么? – davey

0

一个使用Yii当使用多个数据库连接更凉爽方式:

换句话说,你需要1个主分贝来存储用户配置文件和数据库连接;

对于其他从站数据库,您需要一个设置;您将在需要时切换数据库连接。我切换它在我的例如使用用户ID。

我已经使用gii生成了一个从数据库表的模型,我认为你所有的从数据库都具有相同的表结构,并且在该模型之上,我使用了另一个类,如下所示;

'db' => array(
     'class' => 'PortalDbConnection', 
     'connectionString' => 'mysql:host=localhost;dbname=mydb', 
     'username' => 'dev', 
     'password' => '123456', 
     'tablePrefix' => '', 
     'emulatePrepare' => true, 
     'enableParamLogging' => true, 
     'enableProfiling' => true, 
     'charset' => 'utf8', 
    ), 
    'dbx' => array(
     'connectionString' => 'mysql:host=localhost;dbname=mydb1', 
     'username' => 'dev', 
     'password' => '123456', 
     'charset' => 'utf8', 
     'tablePrefix' => '', 
     'autoConnect' => false, 
     'class' => 'CDbConnection', //this may be the reason you get errors! always set this 
    ), 

而现在,为了你的模型的PHP代码:

<?php 

class DomainSlaveM extends Domain { 

    public static function model($className = __CLASS__) { 
     return parent::model($className); 
    } 

    public static $server_id = 1; 
    public static $slave_db; 

public function getDbConnection() { 
    self::$slave_db = Yii::app()->dbx; 
    if (self::$slave_db instanceof CDbConnection) { 
     self::$slave_db->active = false; 
     $config = require(Yii::app()->getBasePath() . '/config/location/flavius.php'); 
     $connectionString = $config['components']['dbx']['connectionString']; 
     self::$slave_db->connectionString = sprintf($connectionString, self::$server_id); 
     self::$slave_db->setActive(true); 
     return self::$slave_db; 
    } 
    else 
     throw new CDbException(Yii::t('yii', 'Active Record requires a "db" CDbConnection application component.')); 
} 

    } 

,并使用它像这样:

public function createDomainSlaveM($model) { 
//switch the db connection; $server_id gets values, from 1 to N 
      DomainSlaveM::$server_id = $model->user_id; 
      $model_domain_slave_m = new DomainSlaveM(); 
      $model_domain_slave_m->attributes = $model->attributes; 
      if ($model_domain_slave_m->validate() && $model_domain_slave_m->save()) { 
       //ok 
      } else { 
       //bad 
      } 
     } 
+0

我知道我可以这样做,但在我的情况下,我不需要多个数据库,只有一个,这取决于你的网址。 – davey