Zend_Db_Tableを利用して複数DBサーバを参照する

DBサーバの負荷分散のために、select文を発行する先のDBを複数用意して運用することがあると思います。マスター(更新&参照)1台に、スレーブ(参照)1台とか。

今回、マスター1台、スレーブ1台の構成で、selectクエリを振り分けるプログラムを作りました。Zend_Db_TableのfetchRow、fetchAll等が呼ばれる度に、クエリを実行するDBサーバを決定します。

まずは、DB接続先の設定をiniファイルに定義します。
接続先情報は、ダミーです。

database.adapter         = Pdo_Mysql
database.params.host     = master.test.com
database.params.username = dbuser
database.params.password = hogehoge
database.params.dbname   = master

# 参照DBhost
database.reference.host  = slave1

次に、Zend_Db_Table_Abstractと各テーブルクラスの間に入れるクラス。
Zend_Db_Table_Abstractクラスの拡張クラスです。

abstract class My_Db_Table_Abstract extends Zend_Db_Table_Abstract
{
    public function fetchAll($where=null, $order=null, $count=null, $offset=null)
    {
        // 2回に1回はmasterに接続
        if ((rand() % 2) == 0) {
            return parent::fetchAll($where, $order, $count, $offset);
        }
        
        // 2回に1回はslaveに接続
        $adapter = $this->getAdapter();
        $this->_setAdapter($this->getReferenceAdapter());
        $rows = parent::fetchAll($where, $order, $count, $offset);
        $this->_setAdapter($adapter);
        
        return $rows;
    }

    public function fetchRow($where=null, $order=null)
    {
        // 2回に1回はmasterに接続
        if ((rand() % 2) == 0) {
            return parent::fetchRow($where, $order);
        }
        
        // 2回に1回はslaveに接続
        $adapter = $this->getAdapter();
        $this->_setAdapter($this->getReferenceAdapter());
        $row = parent::fetchRow($where, $order);
        $this->_setAdapter($adapter);
        
        return $row;
    }
    
    public function getReferenceAdapter()
    {
        if (Zend_Registry::isRegistered('Ref_Db_Adapter')) {
            return Zend_Registry::get('Ref_Db_Adapter');
        }
        
        $config = new Zend_Config_Ini('↑で作ったconfigファイル名');
        $params = $config->database->params->toArray();
        $params['host'] = $config->database->reference->host;
        $db = Zend_Db::factory($config->database->adapter, $params);
        $db->setFetchMode(Zend_Db::FETCH_ASSOC);
        Zend_Registry::set('Ref_Db_Adapter', $db);
        
        return $db;
    }
}

テーブルクラスの定義は以下のように

class Users extends My_Db_Table_Abstract
{
    protected $_name    = 'users';
    protected $_primary = 'user_id';
}

これで、fetchRow、fetchAllを使う際は、masterとslaveにクエリが分散されます