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

}
?>

你可能感兴趣的:(Mysql代理类 支持Master/Slave 读写分离)