Yii框架数据库写分离设计

阅读更多

Yii框架在php中算是个流行的框架了,目前多数开发者都在使用。目前项目中使用mysql数据库主从分离的方式已经成为了常态。在Yii里如何实现呢?

1、首先需要自己写一个数据库的主从连接类。

2、把这个类注册到config目录的main文件里。

3、实现思路是遇到SELECT,SHOW等语句时自动切换到从库。

 

数据库连接类:


	 * 'components'=>array(
	 * 	'db'=>array(
	 * 		'class' => 'DbConnection',
	 * 		'connectionString'=>'mysql://',
	 * 		'slaves'=>array(
	 * 			array('connectionString'=>'mysql://'),
	 * 			array('connectionString'=>'mysql://'),
	 * 		)
	 * 	)
	 * )
	 * 
	 */
	public $slaves = array();
	
	/**
	 * Whether enable the slave database connection.
	 * Defaut is true.Set this property to false for the purpose of only use the master database.
	 * 
	 * @var bool $enableSlave 
	 */
	public $enableSlave = true;
	
	/**
	 * @override
	 * @var bool $autoConnect Whether connect while init
	 */
	//public $autoConnect=false;
	

	/**
	 * @var CDbConnection
	 */
	private $_slave;

	/**
	 * Creates a CDbCommand object for excuting sql statement.
	 * It will detect the sql statement's behavior.
	 * While the sql is a simple read operation.
	 * It will use a slave database connection to contruct a CDbCommand object.
	 * Default it use current connection(master database).
	 * 
	 * @override 
	 * @param string $sql
	 * @return CDbCommand
	 */
	public function createCommand($query = null)
	{
		if ($this->enableSlave && !$this->getCurrentTransaction() && self::isReadOperation($query)) {
			return $this->getSlave()->createCommand($query);
		} else {
			return parent::createCommand($query);
		}
	}

	/**
	 * Construct a slave connection CDbConnection for read operation.
	 * 
	 * @return CDbConnection
	 */
	public function getSlave()
	{
		if (!isset($this->_slave)) {
			foreach ($this->slaves as $slaveConfig) {
				if (!isset($slaveConfig['class']))
					$slaveConfig['class'] = 'CDbConnection';
				try {
					if ($slave = Yii::createComponent($slaveConfig)) {
						Yii::app()->setComponent('dbslave', $slave);
						$this->_slave = $slave;
						break;
					}
				} catch (Exception $e) {
					Yii::log('Create slave database connection failed!', 'warn');
					continue;
				}
			}
			if (!$this->_slave) {
				$this->_slave = clone $this;
				$this->_slave->enableSlave = false;
			}
		}
		return $this->_slave;
	}

	/**
	 * Detect whether the sql statement is just a simple read operation.
	 * Read Operation means this sql will not change any thing ang aspect of the database.
	 * Such as SELECT,DECRIBE,SHOW etc.
	 * On the other hand:UPDATE,INSERT,DELETE is write operation.
	 * 
	 * @return bool
	 */
	public function isReadOperation($sql)
	{
		return !!preg_match('/^\s*(SELECT|SHOW|DESCRIBE|PRAGMA)/i', $sql);
	}

	/**
	 * check Master | slave db is connection 
	 *
	 * @params bool $isSlave
	 * @return void
	 */
	public function ping($isSlave = true)
	{
		if ($isSlave) {
			if ($this->getActive()) {
				$connect = $this->getSlave();
				try {
					$connect->getPdoInstance()->query('SELECT 1');
				} catch (PDOException $e) {
					$connect->setActive(false);
					$connect->setActive(true);
				}
			}
		} else {
			if ($this->getActive()) {
				try {
					$this->getPdoInstance()->query('SELECT 1');
				} catch (PDOException $e) {
					$this->setActive(false);
					$this->setActive(true);
				}
			}
		}
	}
}

 然后把这个类注册到main.php 中:

'public_db_common' => array(
	            'class' => 'DbConnection', //这个就是上面的DbConnection类
	            'connectionString' => "mysql:host=;dbname=;port=",
	            'emulatePrepare' => true,
	            'username' => ,
	            'password' => ,
	            'tablePrefix' => 't_',
	             'charset' => 'utf8',
	            'enableProfiling' => true, //
	            'enableParamLogging' => true, //
	            'slaves' => array(
	                array(
	                    'connectionString' => "mysql:host=;dbname=;port=",
	                    'emulatePrepare' => true,
	                    'username' => ,
	                     'password' => ,
	                    'charset' => 'UTF8',
	                    'tablePrefix' => 't_',
	                    'enableParamLogging' => YII_DEBUG,
	                    'schemaCacheID' => 'cache',
	                    'schemaCachingDuration' => 0,
	                )
	            ),
        ),

 

至于说在程序总的调用,就没有什么区别了。

你可能感兴趣的:(Yii框架数据库写分离设计)