【问题标题】:Dynamically change database connection Yii动态改变数据库连接 Yii
【发布时间】:2013-11-04 15:42:00
【问题描述】:

我正在开展一个项目,该项目将通过一个 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 组件放在一个属性中。他们为什么这样做?恐怕这样连接数据库的次数会超出必要的次数。

【问题讨论】:

    标签: mysql database activerecord yii


    【解决方案1】:

    我使用 model 函数来定义她的数据库连接:

    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."));
        }
    }
    

    ma​​in.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',
    ),
    

    【讨论】:

    • 我不需要多个数据库,只需要一个,它会根据您所在的网址而变化。您将 db 组件放在 $conection 属性中的原因是什么?
    【解决方案2】:

    使用 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
                }
            }
    

    【讨论】:

    • 我知道我可以这样做,但在我的情况下,我不需要多个数据库,只需要一个,这取决于你的 url。
    猜你喜欢
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    相关资源
    最近更新 更多