thinkphpでのデータベース読み書き分離コードの解析


  • 元の生態のsql文を用いて書き込み操作を行う場合、executeを用い、読み取り操作はqueryを用いる.
  • MySQLデータの主従同期はやはりMySQLのメカニズムによって実現されるので、この時MySQL主従同期の遅延問題は最適化する必要があり、遅延時間が長すぎると業務だけでなく、ユーザー体験にも影響を与える.

  • thinkphpコアクラスThinkphp/library/Model.class.phpではqueryメソッド、
          Thinkphp/library/Think/Db/Driver/Mysql.class.php
        /**
         * SQL  
         * @access public
         * @param string $sql  SQL
         * @param mixed $parse        SQL  
         * @return mixed
         */
        public function query($sql,$parse=false) {
            if(!is_bool($parse) && !is_array($parse)) {
                $parse = func_get_args();
                array_shift($parse);
            }
            $sql  =   $this->parseSql($sql,$parse);
            return $this->db->query($sql);
        }
          Thinkphp/library/Think/Db/Driver/Mysql.class.php
        /**
         *           
         * @access public
         * @param string $str  sql  
         * @return mixed
         */
        public function query($str) {
            if(0===stripos($str, 'call')){ //         
                $this->close();
                $this->connected    =   false;
            }
            $this->initConnect(false);
            if ( !$this->_linkID ) return false;
            $this->queryStr = $str;
            //         
            if ( $this->queryID ) {    $this->free();    }
            N('db_query',1);
            //         
            G('queryStartTime');
            $this->queryID = mysql_query($str, $this->_linkID);
            $this->debug();
            if ( false === $this->queryID ) {
                $this->error();
                return false;
            } else {
                $this->numRows = mysql_num_rows($this->queryID);
                return $this->getAll();
            }
        }

    上でデータベースリンクを初期化する場合、initConnect(false)、Thinkphp/library/Think/Db/Dbを呼び出す.class.php,false,trueコード実装に注意する.trueは直接呼び出しマスターライブラリを表し、falseは呼び出し読み書き分離リードライブラリを表す.
        /**
         *         
         * @access protected
         * @param boolean $master     
         * @return void
         */
        protected function initConnect($master=true) {
            if(1 == C('DB_DEPLOY_TYPE'))
                //         
                $this->_linkID = $this->multiConnect($master);
            else
                //       
                if ( !$this->connected ) $this->_linkID = $this->connect();
        }
    
        /**
         *         
         * @access protected
         * @param boolean $master     
         * @return void
         */
        protected function multiConnect($master=false) {
            foreach ($this->config as $key=>$val){
                $_config[$key]      =   explode(',',$val);
            }        
            //          
            if(C('DB_RW_SEPARATE')){
                //          
                if($master)
                    //       
                    $r  =   floor(mt_rand(0,C('DB_MASTER_NUM')-1));
                else{
                    if(is_numeric(C('DB_SLAVE_NO'))) {//       
                        $r = C('DB_SLAVE_NO');
                    }else{
                        //          
                        $r = floor(mt_rand(C('DB_MASTER_NUM'),count($_config['hostname'])-1));   //           
                    }
                }
            }else{
                //           
                $r = floor(mt_rand(0,count($_config['hostname'])-1));   //           
            }
            $db_config = array(
                'username'  =>  isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
                'password'  =>  isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
                'hostname'  =>  isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
                'hostport'  =>  isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
                'database'  =>  isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
                'dsn'       =>  isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
                'params'    =>  isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0],
                'charset'   =>  isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],            
            );
            return $this->connect($db_config,$r);
        }

    Queryメソッドパラメータはfalseであり、その他は読み取りマスターライブラリを削除、更新、追加します.これはThinkphp/library/Modelと組み合わせることができます.class.phpのdelete、save、add操作、パラメータはtrueです.