Esempio n. 1
0
 /**
  * @brief 获取db对象
  *
  * @param $clusterName 集群名称
  * @param $key 负载均衡key
  * @param $getNew 是否重新连接
  *
  * @return 
  */
 public static function getConn($clusterName, $key = NULL, $getNew = false)
 {
     $hookBeforeInit = Bd_Conf::getConf('/db/hook_before_init');
     if ($hookBeforeInit === false) {
         //cannot find hookBeforeInit in conf file
         self::$_error['errno'] = LOAD_CONF_ERROR;
         self::$_error['error'] = 'Can not read hookBeforeInit, please check db/global.conf';
         //Bd_Log::warning(self::$_error['error'],self::$_error['errno']);
         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
         return false;
     }
     if ($hookBeforeInit != NULL) {
         //user sets hookBeforeInit
         if (is_callable($hookBeforeInit)) {
             $clusterName = call_user_func($hookBeforeInit, $clusterName);
         } else {
             //warnning
             self::$_error['errno'] = SET_HOOK_ERROR;
             self::$_error['error'] = 'Hook(beforinit):' . $before . 'is not callable';
             //Bd_Log::warning(self::$_error['error'],self::$_error['errno']);
             Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
         }
     }
     $conf =& self::$_conf;
     $hosts =& self::$_hosts;
     $dbData =& self::$_dbData;
     $lastDb =& self::$_lastDb;
     //(1) alreay save a connection (2)user do not need to recreate
     if (!empty($lastDb[$clusterName]) && !$getNew) {
         //Bd_Log::trace('Return an existing connection',0,array('db_cluster'=>$clusterName));
         return $lastDb[$clusterName];
     }
     if (self::_init($clusterName) === false) {
         return false;
     }
     //create a new db object
     $db = new Bd_DB(Bd_Db_ConnMgr::$ENABLE_PROFILING);
     //add hook
     if ('' !== ($before = $conf['hook_before_query'])) {
         if (!$db->addHook(Bd_Db::HK_BEFORE_QUERY, $clusterName . '-before', $before)) {
             self::$_error['errno'] = SET_HOOK_ERROR;
             self::$_error['error'] = 'Hook(befor query):' . $before . ' is not callable';
             //Bd_Log::warning(self::$_error['error'],self::$_error['errno']);
             Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
         }
     }
     if ('' !== ($after = $conf['hook_after_query'])) {
         if (!$db->addHook(Bd_Db::HK_AFTER_QUERY, $clusterName . '-after', $after)) {
             self::$_error['errno'] = SET_HOOK_ERROR;
             self::$_error['error'] = 'Hook(after query):' . $after . ' is not callable';
             //Bd_Log::warning(self::$_error['error'],self::$_error['errno']);
             Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
         }
     }
     if ('' !== ($onFail = $conf['hook_on_fail'])) {
         if (!$db->onFail($onFail)) {
             self::$_error['errno'] = SET_HOOK_ERROR;
             self::$_error['error'] = 'Hook(on fail):' . $onFail . ' is not callable';
             //Bd_Log::warning(self::$_error['error'],self::$_error['errno']);
             Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
         }
     }
     //try to connect host until there is not host or connecting successfully
     while (true) {
         //balancer could not select a valid host to connect
         if (count($hosts['valid_hosts']) === 0 || ($index = $dbData['host_selector']->select($hosts, $key)) === false) {
             self::$_error['errno'] = ALL_CONNECT_ERROR;
             self::$_error['error'] = 'No host could be connected in the cluster';
             //                 Bd_Log::warning(
             //                             self::$_error['error'],
             //                             self::$_error['errno'],
             //                             array('db_cluster'=>$clusterName)
             //                         );
             Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
             $hookOnConnFail = $conf['hook_on_connect_fail'];
             if ($hookOnConnFail != NULL) {
                 if (is_callable($hookOnConnFail)) {
                     call_user_func($hookOnConnFail);
                 } else {
                     //warnning
                     self::$_error['errno'] = SET_HOOK_ERROR;
                     self::$_error['error'] = 'Hook(on connect fail):' . $hookOnConnFail . 'is not callable';
                     //Bd_Log::warning(self::$_error['error'],self::$_error['errno']);
                     Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
                 }
             }
             return false;
         }
         //log parameters
         $logPara = array('db_cluster' => $clusterName, 'db_host' => $hosts['valid_hosts'][$index]['ip'], 'db_port' => $hosts['valid_hosts'][$index]['port'], 'default_db' => $conf['default_db']);
         for ($i = 1; $i <= $conf['retry_times']; $i++) {
             $timeout = $conf['connect_timeout_s'];
             if ($timeout > 0) {
                 $db->setConnectTimeOut($timeout);
             }
             $r_timeout = $conf['read_timeout_s'];
             if ($r_timeout > 0) {
                 $db->setOption(MYSQL_OPT_READ_TIMEOUT, $r_timeout);
             }
             $w_timeout = $conf['write_timeout_s'];
             if ($w_timeout > 0) {
                 $db->setOption(MYSQL_OPT_WRITE_TIMEOUT, $w_timeout);
             }
             //Bd_Log::debug("retry times: $i");
             Bd_Db_RALLog::warning(RAL_LOG_DEBUG, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", 0, "retry times: {$i}");
             $start = microtime(true) * 1000;
             //connect
             $ret = $db->connect($hosts['valid_hosts'][$index]['ip'], $conf['username'], $conf['password'], $conf['default_db'], $hosts['valid_hosts'][$index]['port'], $conf['connect_flag']);
             $end = microtime(true) * 1000;
             if ($ret) {
                 if (empty($conf['charset']) || $db->charset($conf['charset'])) {
                     $logPara['time_ms'] = $end - $start;
                     //Bd_Log::trace('Connect to Mysql successfully',0,$logPara);
                     $lastDb[$clusterName] = $db;
                     return $lastDb[$clusterName];
                 } else {
                     //Bd_Log::debug('Set charset failed');
                     Bd_Db_RALLog::warning(RAL_LOG_DEBUG, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", 0, 'Set charset failed');
                 }
             }
         }
         //connect failed
         self::$_error['errno'] = CONNECT_ERROR;
         self::$_error['error'] = 'Connect to Mysql failed';
         //Bd_Log::warning(self::$_error['error'],self::$_error['errno'],$logPara);
         Bd_Db_RALLog::warning(RAL_LOG_WARN, "ConnMgr", $clusterName, "getConn", "", 0, 0, 0, 0, 0, $clusterName, "", self::$_error['errno'], self::$_error['error']);
         self::_recordFailedHost($index);
     }
     return false;
 }
Esempio n. 2
0
 public function doSql($strSql, $fetchType = Bd_DB::FETCH_ASSOC, $bolUseResult = false)
 {
     // check the env before do sql query;
     //is in transaction is set outer;
     if ($this->_bolIsInTransaction) {
         if ($this->_intUseConnectionNum > 1) {
             return false;
         }
         $this->_intAffectedRows = 0;
         $this->_arrQueryError = array();
         $this->_bolIsSqlTransformError = false;
     } else {
         //clear the last query;
         $this->reset();
     }
     $this->_timer->start();
     $arrSql = transform($this->_strDBName, $strSql, $this->_strConfPath, $this->_strConfFilename);
     $this->_transTime += $this->_timer->stop();
     if (NULL === $arrSql || $arrSql['err_no'] !== 0) {
         $this->_bolIsSqlTransformError = true;
         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'transform', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, $this->_transTime, '', $strSql, self::$TRANSFORM_ERRNO, self::$TRANSFORM_ERROR);
         return false;
     }
     //some check before conneciton;
     if (BD_DB_SplitDB::SPLITDB_SQL_SELECT === $arrSql['sql_type'] && $bolUseResult === true) {
         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'check', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, 0, '', $strSql, self::$COMMON_ERRNO, "select should be store result");
         return false;
     }
     $arrSplitIndex = $this->analyseSqlTransResult($arrSql, BD_DB_SplitDB::MAX_SQL_SPLIT_COUNT);
     if (!$arrSplitIndex || count($arrSplitIndex) <= 0) {
         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'check', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, 0, '', $strSql, self::$COMMON_ERRNO, "splitindex count error");
         return false;
     }
     //open the connection;
     if ($this->_bolIsInTransaction) {
         // in transaction, only 1 split is ok;
         if (count($arrSplitIndex) !== 1) {
             Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'check', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, 0, '', $strSql, self::$COMMON_ERRNO, "in transaction split count should be 1");
             return false;
         }
         //in transaction , the new sql split index should be the same as the last one;
         if ($this->_intUseConnectionNum === 1) {
             if ($arrSplitIndex[0] !== $this->_intLastDBNum) {
                 Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'check', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, 0, '', $strSql, self::$COMMON_ERRNO, "in transaction connect should be the same");
                 return false;
             }
         } else {
             if ($arrSplitIndex[0] === -1) {
                 $strDBInstanceName = $this->_strDBName;
             } else {
                 $strDBInstanceName = $this->_strDBName . $arrSplitIndex[0];
             }
             if (is_null($this->_arrMysql[$strDBInstanceName])) {
                 $ret = $this->connect($strDBInstanceName);
                 if (!$ret) {
                     $this->_arrQueryError[$strDBInstanceName] = '';
                     return false;
                 }
             } else {
                 //echo "connection exist!\n";
             }
             $this->_arrMysql[$strDBInstanceName]->query('START TRANSACTION');
             $this->_intLastDBNum = $arrSql['sqls'][0]['splitdb_index'];
             $this->_intUseConnectionNum = 1;
         }
     } else {
         foreach ($arrSplitIndex as $intSplitIndex) {
             if ($intSplitIndex === -1) {
                 $strDBInstanceName = $this->_strDBName;
             } else {
                 $strDBInstanceName = $this->_strDBName . $intSplitIndex;
             }
             if (is_null($this->_arrMysql[$strDBInstanceName])) {
                 $ret = $this->connect($strDBInstanceName);
                 if (!$ret) {
                     $this->_arrQueryError[$strDBInstanceName] = '';
                     break;
                 }
             } else {
                 //echo "connection exist!\n";
             }
             $this->_intUseConnectionNum++;
         }
         if ($this->_intUseConnectionNum !== count($arrSplitIndex)) {
             $this->_intUseConnectionNum = 0;
             return false;
         }
         if ($this->_intUseConnectionNum === 1) {
             $this->_intLastDBNum = $arrSplitIndex[0];
         }
     }
     //build result
     switch ($fetchType) {
         case Bd_DB::FETCH_OBJ:
             $ret = new Bd_Db_SplitDBResult();
             break;
         case Bd_DB::FETCH_ASSOC:
             $ret = array();
             break;
         case Bd_DB::FETCH_ROW:
             $ret = array();
             break;
         default:
             Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'check', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, 0, '', $strSql, self::$COMMON_ERRNO, "fetch type error");
             return false;
     }
     // execute hooks before query
     foreach ($this->hkBeforeQ as $arrCallback) {
         $func = $arrCallback[0];
         $extArgs = $arrCallback[1];
         if (call_user_func_array($func, array($this, &$sql, $extArgs)) === false) {
             Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'query', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, 0, 0, 0, '', $strSql, self::$COMMON_ERRNO, "execute hooks before query fail");
             return false;
         }
     }
     //do sql query
     //at least one success
     $bolAtLeastOneSuccess = false;
     foreach ($arrSql['sqls'] as $oneSql) {
         if ($oneSql['splitdb_index'] === -1) {
             $strDBInstanceName = $this->_strDBName;
         } else {
             $strDBInstanceName = $this->_strDBName . $oneSql['splitdb_index'];
         }
         $this->_timer->start();
         $res = $this->_arrMysql[$strDBInstanceName]->query($oneSql['sql'], $bolUseResult ? MYSQLI_USE_RESULT : MYSQLI_STORE_RESULT);
         $time = $this->_timer->stop();
         $this->_queryTime += $time;
         if (is_bool($res) || $res === NULL) {
             $ok = $res == true;
             // call fail handler
             if (!$ok) {
                 //echo "query fail {$oneSql['sql']}\n";
                 if ($arrSql['sql_type'] === BD_DB_SplitDB::SPLITDB_SQL_SELECT) {
                     if (is_null($this->_arrQueryError[$strDBInstanceName])) {
                         $this->_arrQueryError[$strDBInstanceName] = $oneSql['sql'];
                     }
                     continue;
                 } else {
                     if (($arrSql['sql_type'] === BD_DB_SplitDB::SPLITDB_SQL_UPDATE || $arrSql['sql_type'] === BD_DB_SplitDB::SPLITDB_SQL_DELETE) && $this->_arrMysql[$strDBInstanceName]->errno === BD_DB_SplitDB::MYSQL_ERR_TABLE_NOT_EXIST && $arrSql['table_split_type'] === BD_DB_SplitDB::SPLITDB_SPLIT_TYPE_RANGE) {
                         //echo "delete or update fail!\n";
                         continue;
                     } else {
                         if (is_null($this->_arrQueryError[$strDBInstanceName])) {
                             $this->_arrQueryError[$strDBInstanceName] = $oneSql['sql'];
                         }
                         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'query', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, round($time / 1000), 0, 0, $strDBInstanceName, $oneSql['sql'], self::$QUERY_ERRNO, self::$QUERY_ERROR);
                         if ($this->onfail !== NULL) {
                             call_user_func_array($this->onfail, array($this, &$ok));
                         }
                         return false;
                     }
                 }
             } else {
                 //commit query success
                 if ($this->_arrMysql[$strDBInstanceName]->affected_rows >= 0) {
                     $this->_intAffectedRows += $this->_arrMysql[$strDBInstanceName]->affected_rows;
                 }
             }
         } else {
             //mysqli_result object returned
             if ($arrSql['sql_type'] === BD_DB_SplitDB::SPLITDB_SQL_SELECT) {
                 //add to result
                 switch ($fetchType) {
                     case Bd_DB::FETCH_OBJ:
                         $ret->addresult($res);
                         break;
                     case Bd_DB::FETCH_ASSOC:
                         while ($row = $res->fetch_assoc()) {
                             $ret[] = $row;
                         }
                         $res->free();
                         break;
                     case Bd_DB::FETCH_ROW:
                         while ($row = $res->fetch_row()) {
                             $ret[] = $row;
                         }
                         $res->free();
                         break;
                     default:
                         return false;
                 }
                 //echo "query success ".$oneSql['sql']."\n";
                 $bolAtLeastOneSuccess = true;
                 $this->_intAffectedRows = count($ret);
             }
         }
     }
     if ($arrSql['sql_type'] === BD_DB_SplitDB::SPLITDB_SQL_SELECT && !$bolAtLeastOneSuccess) {
         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "SplitDB", $this->_strDBName, 'query', '', $this->_timer->getTotalTime(Bd_Timer::PRECISION_MS), 0, round($this->_queryTime / 1000), 0, 0, '', $strSql, self::$QUERY_ERRNO, self::$QUERY_ERROR);
         if ($this->onfail !== NULL) {
             call_user_func_array($this->onfail, array($this, &$ret));
         }
         return false;
     }
     // execute hooks after query
     foreach ($this->hkAfterQ as $arrCallback) {
         $func = $arrCallback[0];
         $extArgs = $arrCallback[1];
         call_user_func_array($func, array($this, &$ret, $extArgs));
     }
     if ($arrSql['sql_type'] !== BD_DB_SplitDB::SPLITDB_SQL_SELECT) {
         $ret = true;
     }
     return $ret;
 }
Esempio n. 3
0
 /**
  * @brief prepare查询接口
  *
  * @param $query 查询语句
  * @param $getRaw 是否返回原始的mysqli_stmt对象
  *
  * @return 
  */
 public function prepare($query, $getRaw = false)
 {
     $stmt = $this->mysql->prepare($query);
     if ($stmt === false) {
         Bd_Db_RALLog::warning(RAL_LOG_SUM_FAIL, "Bd_DB", $this->dbConf['dbname'], "prepare", "{$this->dbConf['host']}:{$this->dbConf['port']}", 0, 0, 0, 0, 0, $this->dbConf['dbname'], $query, $this->mysql->errno, $this->mysql->error);
         return false;
     }
     if ($getRaw) {
         return $stmt;
     } else {
         return new Bd_Db_DBStmt($stmt);
     }
 }