Mysql代理類 支持Master/Slave 讀寫分離

/**
* 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;
	}

}
?>
相關文章
相關標籤/搜索