Yii實(shí)現(xiàn)MySQL多數(shù)據(jù)庫(kù)和讀寫(xiě)分離實(shí)例分析
本文實(shí)例分析了Yii實(shí)現(xiàn)MySQL多數(shù)據(jù)庫(kù)和讀寫(xiě)分離的方法。分享給大家供大家參考。具體分析如下:
Yii Framework是一個(gè)基于組件、用于開(kāi)發(fā)大型 Web 應(yīng)用的高性能 PHP 框架。Yii提供了今日Web 2.0應(yīng)用開(kāi)發(fā)所需要的幾乎一切功能,也是最強(qiáng)大的框架之一,下文我們來(lái)介紹Yii實(shí)現(xiàn)MySQL多庫(kù)和讀寫(xiě)分離的方法
前段時(shí)間為SNS產(chǎn)品做了架構(gòu)設(shè)計(jì),在程序框架方面做了不少相關(guān)的壓力測(cè)試,最終選定了YiiFramework,至于為什么沒(méi)選用公司內(nèi)部的 PHP框架,其實(shí)理由很充分,公司的框架雖然是"前輩"們辛苦的積累,但畢竟不夠成熟,沒(méi)有大型項(xiàng)目的歷練,猶如一個(gè)涉世未深的年輕小伙。Yii作為一個(gè) 頗有名氣開(kāi)源產(chǎn)品,必定有很多人在使用,意味著有一批人在維護(hù),而且在這之前,我也使用Yii開(kāi)發(fā)過(guò)大型項(xiàng)目,Yii的設(shè)計(jì)模式和它的易擴(kuò)展特性足以堪當(dāng)重任。
SNS同一般的社交產(chǎn)品不同的就是它最終要承受大并發(fā)和大數(shù)據(jù)量的考驗(yàn),架構(gòu)設(shè)計(jì)時(shí)就要考慮這些問(wèn)題, web分布式、負(fù)載均衡、分布式文件存儲(chǔ)、MySQL分布式或讀寫(xiě)分離、NoSQL以及各種緩存,這些都是必不可少的應(yīng)用方案,本文所講的就是MySQL 分庫(kù)和主從讀寫(xiě)分離在Yii的配置和使用。
Yii默認(rèn)是不支持讀寫(xiě)分離的,我們可以利用Yii的事件驅(qū)動(dòng)模式來(lái)實(shí)現(xiàn)MySQL的讀寫(xiě)分離。
Yii提供了一個(gè)強(qiáng)大的CActiveRecord數(shù)據(jù)庫(kù)操作類(lèi),通過(guò)重寫(xiě)getDbConnection方法來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的切換,然后通過(guò)事件 beforeSave、beforeDelete、beforeFind 來(lái)實(shí)現(xiàn)讀寫(xiě)服務(wù)器的切換,還需要兩個(gè)配置文件dbconfig和modelconfig分別配置數(shù)據(jù)庫(kù)主從服務(wù)器和model所對(duì)應(yīng)的數(shù)據(jù)庫(kù)名稱(chēng),附代碼
DBConfig.php文件如下:
return array(
'passport' => array(
'write' => array(
'class' => 'CDbConnection',
'connectionString' => 'mysql:host=10.1.39.2;dbname=db1′,
'emulatePrepare' => true,
//'enableParamLogging' => true,
'enableProfiling' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8′,
'schemaCachingDuration'=>3600,
),
'read' => array(
array(
'class' => 'CDbConnection',
'connectionString' => 'mysql:host=10.1.39.3;dbname=db1,
'emulatePrepare' => true,
//'enableParamLogging' => true,
'enableProfiling' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8′,
'schemaCachingDuration'=>3600,
),
array(
'class' => 'CDbConnection',
'connectionString' => 'mysql:host=10.1.39.4;dbname=db3′,
'emulatePrepare' => true,
//'enableParamLogging' => true,
'enableProfiling' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8′,
'schemaCachingDuration'=>3600,
),
),
),
);
ModelConfig.php如下:
return array(
//key為數(shù)據(jù)庫(kù)名稱(chēng),value為Model
'passport' => array('User','Post'),
'microblog' => array('…'),
);
?>
ActiveRecord.php如下:
* 基于CActiveRecord類(lèi)的封裝,實(shí)現(xiàn)多庫(kù)和主從讀寫(xiě)分離
* 所有Model都必須繼承些類(lèi).
*
*/
class ActiveRecord extends CActiveRecord
{
//model配置
public $modelConfig = '';
//數(shù)據(jù)庫(kù)配置
public $dbConfig = '';
//定義一個(gè)多數(shù)據(jù)庫(kù)集合
static $dataBase = array();
//當(dāng)前數(shù)據(jù)庫(kù)名稱(chēng)
public $dbName = '';
//定義庫(kù)類(lèi)型(讀或?qū)?
public $dbType = 'read'; //'read' or 'write'
/**
* 在原有基礎(chǔ)上添加了一個(gè)dbname參數(shù)
* @param string $scenario Model的應(yīng)用場(chǎng)景
* @param string $dbname 數(shù)據(jù)庫(kù)名稱(chēng)
*/
public function __construct($scenario='insert', $dbname = '')
{
if (!empty($dbname))
$this->dbName = $dbname;
parent::__construct($scenario);
}
/**
* 重寫(xiě)父類(lèi)的getDbConnection方法
* 多庫(kù)和主從都在這里切換
*/
public function getDbConnection()
{
//如果指定的數(shù)據(jù)庫(kù)對(duì)象存在則直接返回
if (self::$dataBase[$this->dbName]!==null)
return self::$dataBase[$this->dbName];
if ($this->dbName == 'db'){
self::$dataBase[$this->dbName] = Yii::app()->getDb();
}else{
$this->changeConn($this->dbType);
}
if(self::$dataBase[$this->dbName] instanceof CDbConnection){
self::$dataBase[$this->dbName]->setActive(true);
return self::$dataBase[$this->dbName];
} else
throw new CDbException(Yii::t('yii','Model requires a "db" CDbConnection application component.'));
}
/**
* 獲取配置文件
* @param unknown_type $type
* @param unknown_type $key
*/
private function getConfig($type="modelConfig",$key="){
$config = Yii::app()->params[$type];
if($key)
$config = $config[$key];
return $config;
}
/**
* 獲取數(shù)據(jù)庫(kù)名稱(chēng)
*/
private function getDbName(){
if($this->dbName)
return $this->dbName;
$modelName = get_class($this->model());
$this->modelConfig = $this->getConfig('modelConfig');
//獲取model所對(duì)應(yīng)的數(shù)據(jù)庫(kù)名
if($this->modelConfig)foreach($this->modelConfig as $key=>$val){
if(in_array($modelName,$val)){
$dbName = $key;
break;
}
}
return $dbName;
}
/**
* 切換數(shù)據(jù)庫(kù)連接
* @param unknown_type $dbtype
*/
protected function changeConn($dbtype = 'read'){
if($this->dbType == $dbtype && self::$dataBase[$this->dbName] !== null)
return self::$dataBase[$this->dbName];
$this->dbName = $this->getDbName();
if(Yii::app()->getComponent($this->dbName.'_'.$dbtype) !== null){
self::$dataBase[$this->dbName] = Yii::app()->getComponent($this->dbName.'_'.$dbtype);
return self::$dataBase[$this->dbName];
}
$this->dbConfig = $this->getConfig('dbConfig',$this->dbName);
//跟據(jù)類(lèi)型取對(duì)應(yīng)的配置(從庫(kù)是隨機(jī)值)
if($dbtype == 'write'){
$config = $this->dbConfig[$dbtype];
}else{
$slavekey = array_rand($this->dbConfig[$dbtype]);
$config = $this->dbConfig[$dbtype][$slavekey];
}
//將數(shù)據(jù)庫(kù)配置加到component中
if($dbComponent = Yii::createComponent($config)){
Yii::app()->setComponent($this->dbName.'_'.$dbtype,$dbComponent);
self::$dataBase[$this->dbName] = Yii::app()->getComponent($this->dbName.'_'.$dbtype);
$this->dbType = $dbtype;
return self::$dataBase[$this->dbName];
} else
throw new CDbException(Yii::t('yii','Model requires a "changeConn" CDbConnection application component.'));
}
/**
* 保存數(shù)據(jù)前選擇 主 數(shù)據(jù)庫(kù)
*/
protected function beforeSave(){
parent::beforeSave();
$this->changeConn('write');
return true;
}
/**
* 刪除數(shù)據(jù)前選擇 主 數(shù)據(jù)庫(kù)
*/
protected function beforeDelete(){
parent::beforeDelete();
$this->changeConn('write');
return true;
}
/**
* 讀取數(shù)據(jù)選擇 從 數(shù)據(jù)庫(kù)
*/
protected function beforeFind(){
parent::beforeFind();
$this->changeConn('read');
return true;
}
/**
* 獲取master庫(kù)對(duì)象
*/
public function dbWrite(){
return $this->changeConn('write');
}
/**
* 獲取slave庫(kù)對(duì)象
*/
public function dbRead(){
return $this->changeConn('read');
}
}
這是我寫(xiě)好的類(lèi),放在components文件夾里,然后所有的Model都繼承ActiveRecord類(lèi)就可以實(shí)現(xiàn)多庫(kù)和主從讀寫(xiě)分離了,至于如何支持原生的SQL也同時(shí)使用讀寫(xiě)分離,此類(lèi)都已經(jīng)實(shí)現(xiàn)。
希望本文所述對(duì)大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
- yii框架結(jié)合charjs實(shí)現(xiàn)統(tǒng)計(jì)30天數(shù)據(jù)的方法
- yii 框架實(shí)現(xiàn)按天,月,年,自定義時(shí)間段統(tǒng)計(jì)數(shù)據(jù)的方法分析
- Yii統(tǒng)計(jì)不同類(lèi)型郵箱數(shù)量的方法
- Yii中的relations數(shù)據(jù)關(guān)聯(lián)查詢(xún)及統(tǒng)計(jì)功能用法詳解
- 解析yii數(shù)據(jù)庫(kù)的增刪查改
- Yii2 批量插入、更新數(shù)據(jù)實(shí)例
- Yii2框架數(shù)據(jù)庫(kù)簡(jiǎn)單的增刪改查語(yǔ)法小結(jié)
- Yii2.0高級(jí)框架數(shù)據(jù)庫(kù)增刪改查的一些操作
- yii框架表單模型使用及以數(shù)組形式提交表單數(shù)據(jù)示例
- Yii+MYSQL鎖表防止并發(fā)情況下重復(fù)數(shù)據(jù)的方法
- Yii實(shí)現(xiàn)多數(shù)據(jù)庫(kù)主從讀寫(xiě)分離的方法
- yii框架結(jié)合charjs統(tǒng)計(jì)上一年與當(dāng)前年數(shù)據(jù)的方法示例
相關(guān)文章
laravel實(shí)現(xiàn)于語(yǔ)言包的完美切換方法
今天小編就為大家分享一篇laravel實(shí)現(xiàn)于語(yǔ)言包的完美切換方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09PHP用戶(hù)驗(yàn)證和標(biāo)簽推薦的簡(jiǎn)單使用
這篇文章主要介紹了PHP用戶(hù)驗(yàn)證和標(biāo)簽推薦的簡(jiǎn)單使用,本文給大家介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10ThinkPHP表單自動(dòng)驗(yàn)證實(shí)例
這篇文章主要介紹了ThinkPHP表單自動(dòng)驗(yàn)證實(shí)例,是ThinkPHP三大自動(dòng)中非常常用的一個(gè)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10利用PHP fsockopen 模擬POST/GET傳送數(shù)據(jù)的方法
使用php可以模擬post和get傳送數(shù)據(jù)到別的網(wǎng)頁(yè)或者是站點(diǎn),那么怎么傳送數(shù)據(jù)呢?下面由小編給大家介紹利用PHP fsockopen 模擬POST/GET傳送數(shù)據(jù)的方法,需要的朋友一起看看吧2015-09-09php+mysql寫(xiě)的簡(jiǎn)單留言本實(shí)例代碼
方便新手學(xué)習(xí)php2008-07-07php多種形式發(fā)送郵件(mail qmail郵件系統(tǒng) phpmailer類(lèi))
這篇文章主要介紹了php多種形式發(fā)送郵件的方法,包括使用mail()函數(shù)、使用管道的形式、使用phpmailer類(lèi)等方法,大家參考使用吧2014-01-01PHP利用pdo_odbc實(shí)現(xiàn)連接數(shù)據(jù)庫(kù)示例【基于ThinkPHP5.1搭建的項(xiàng)目】
這篇文章主要介紹了PHP利用pdo_odbc實(shí)現(xiàn)連接數(shù)據(jù)庫(kù),結(jié)合實(shí)例形式分析了基于ThinkPHP5.1框架使用pdo_odbc連接數(shù)據(jù)庫(kù)相關(guān)操作步驟與實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-05-05記Laravel調(diào)用Gin接口調(diào)用formData上傳文件的實(shí)現(xiàn)方法
這篇文章主要介紹了記Laravel調(diào)用Gin接口調(diào)用formData上傳文件的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12