/** * Mysql代理類 支持Master/Slave 讀寫分離 客戶端不需擔憂連Master/Slave 本類自動代理完成 * * @author 小黑米 * @package Core.DB * @version 1.0 beat * @copyright 2008-5-8 * @todo 下一步準備開發支持多memcache的代理 */ /* 配置: $dns = array( array(//第一個爲主庫 "host"=>"localhost", "user"=>"root", "pwd"=>"123456", "port"=>3306, "db"=>"phpexp", ), //剩下的都是從庫 array( "host"=>"localhost", "user"=>"root", "pwd"=>"123456", "port"=>3306, "db"=>"phpexp", ), ); 執行方法: Mysql::getInstance()->fetchResult("select * from frame_role"); Mysql::getInstance()->query("update frame_role set name=test limit 1"); SQL記錄追蹤: array(2) { ["times"] => int(2) ["sqls"] => array(2) { [0] => array(2) { ["sql"] => string(24) "select * from frame_role" ["type"] => string(5) "slave" } [1] => array(2) { ["sql"] => string(39) "update frame_role set name=test limit 1" ["type"] => string(6) "master" } } } 執行結果: array(2) { [0] => array(4) { ["id"] => string(1) "1" ["rname"] => string(7) "tourisa" ["rmark"] => string(6) "遊客" ["rprev"] => string(6) "a:0:{}" } [1] => array(4) { ["id"] => string(1) "2" ["rname"] => string(7) "tourise" ["rmark"] => string(7) "遊客1" ["rprev"] => string(6) "a:0:{}" } } */ class Mysql{ /** * 單例模式 * * @var resource */ private static $instance = null; /** * Master 單例 * * @var resource */ private static $master = null; /** * Slave 單例 * * @var resource */ private static $slave = null; /** * 數據庫執行記錄 * * @var array */ public static $querys = array("times"=>0,"sqls"=>array()); private $_tmpRes = null; /** * 獲取單例 * * @return resource */ public static function getInstance(){ if(!self::$instance) { self::$instance = new Mysql(); } return self::$instance; } /** * 構造函數 保留 * */ private function __construct(){} /** * 取記錄 並根據自動hash結果集 * * @param string $sql * @param string $hashBy * @return array */ public function fetchResult($sql,$hashBy=null){ $return = array(); $this->query($sql); if(!$this->_tmpRes) httpError("handler500","SQL:{$sql} 執行失敗"); if(!$hashBy) { while ($res = mysql_fetch_assoc($this->_tmpRes)) { $return[] = $res; } } else { while ($res = mysql_fetch_assoc($this->_tmpRes)) { $return[$res[$hashBy]] = $res; } } return $return; } /** * 執行指令 * * @param string $sql * @return resource */ public function query($sql){ self::$querys['times']++; $conn = $this->_checkSql($sql); self::$querys['sqls'][] = array("sql"=>$sql,"type"=>$conn['type']); // d(mysql_query($sql,$this->conn) or die(mysql_error()),false); $this->_tmpRes = mysql_query($sql,$conn['conn']) or httpError("handler500",mysql_error()); } /** * 分析SQL語句,自動分配到主庫,從庫 * * @param string $sql * @return resource */ private function _checkSql($sql){ global $dns; $_n = count($dns); if(count($dns)===1) {//主從同樣 return $this->_getHelper($dns[0],"master"); } else { $type = substr($sql,0,strpos($sql," ")); if ($type === 'select') {//讀從庫 if($_n=2) { $ddns = $dns[1]; } else {//隨即取一個從庫 $ddns = $dns[mt_rand(1,$_n-1)]; } return $this->_getHelper($ddns); } else {//更新主庫 return $this->_getHelper($dns[0],"master"); } } } /** * 主從庫助手函數 * * @param array $dns * @param string $type Slave/Master * @return resource */ private function _getHelper($dns,$type="slave"){ if(!self::$$type) { self::$$type = new Helper($dns); } return array("conn"=>self::$$type->getConn(),"type"=>$type); } /** * 影響記錄數 * * @param string $sql * @return array */ public function getAffectRows(){ return mysql_affected_rows(); } /** * 最後插入的ID * * @param string $sql * @return array */ public function getLastInsertId(){ return mysql_insert_id(); } } class Helper{ private $conn = null; public function __construct(&$dns){ $this->conn = mysql_connect($dns['host'].":".$dns['port'],$dns['user'],$dns['pwd']) or httpError("handler500","數據庫出錯"); mysql_select_db($dns['db'],$this->conn) or httpError("handler500",$dns['db']."庫出現異常"); } public function getConn(){ return $this->conn; } } ?>