当前位置:首页 > CMS教程 > 其它CMS > 列表

Yii实现多数据库主从读写分离的方法

发布:smiling 来源: PHP粉丝网  添加日期:2021-05-05 12:40:05 浏览: 评论:0 

这篇文章主要介绍了Yii实现多数据库主从读写分离的方法,通过针对Yii数据库类的扩展实现多数据库主从读写的分离功能,是非常实用的技巧,需要的朋友可以参考下

本文实例讲述了Yii实现多数据库主从读写分离的方法。分享给大家供大家参考。具体分析如下:

Yii框架数据库多数据库、主从、读写分离 实现,功能描述:

1.实现主从数据库读写分离 主库:写 从库(可多个):读

2.主数据库无法连接时 可设置从数据库是否 可写

3.所有从数据库无法连接时 可设置主数据库是否 可读

4.如果从数据库连接失败 可设置N秒内不再连接

利用yii扩展实现,代码如下:

  1. <?php 
  2. /** 
  3.  * 主数据库 写 从数据库(可多个)读 
  4.  * 实现主从数据库 读写分离 主服务器无法连接 从服务器可切换写功能 
  5.  * 从务器无法连接 主服务器可切换读功 
  6.  * by lmt 
  7.  * */ 
  8. class DbConnectionMan extends CDbConnection { 
  9.     public $timeout = 10; //连接超时时间 
  10.     public $markDeadSeconds = 600; //如果从数据库连接失败 600秒内不再连接  
  11.     //用 cache 作为缓存全局标记 
  12.     public $cacheID = 'cache'
  13.  
  14.     /** 
  15.      * @var array $slaves.Slave database connection(Read) config array. 
  16.      * 配置符合 CDbConnection. 
  17.      * @example 
  18.      * 'components'=>array( 
  19.      *   'db'=>array( 
  20.      *    'connectionString'=>'mysql://<master>', 
  21.      *    'slaves'=>array( 
  22.      *     array('connectionString'=>'mysql://<slave01>'), 
  23.      *     array('connectionString'=>'mysql://<slave02>'), 
  24.      *    ) 
  25.      *   ) 
  26.      * ) 
  27.      * */ 
  28.     public $slaves = array(); 
  29.     /** 
  30.      *  
  31.      * 从数据库状态 false 则只用主数据库 
  32.      * @var bool $enableSlave 
  33.      * */ 
  34.     public $enableSlave = true; 
  35.  
  36.     /** 
  37.      * @var slavesWrite 紧急情况主数据库无法连接 切换从服务器(读写). 
  38.      */ 
  39.     public $slavesWrite = false; 
  40.  
  41.     /** 
  42.      * @var masterRead 紧急情况从主数据库无法连接 切换从住服务器(读写). 
  43.      */ 
  44.     public $masterRead = false; 
  45.  
  46.     /** 
  47.      * @var _slave 
  48.      */ 
  49.     private $_slave
  50.  
  51.     /** 
  52.      * @var _disableWrite 从服务器(只读). 
  53.      */ 
  54.     private $_disableWrite = true; 
  55.  
  56.     /** 
  57.      * 
  58.      * 重写 createCommand 方法,1.开启从库 2.存在从库 3.当前不处于一个事务中 4.从库读数据 
  59.      * @param string $sql 
  60.      * @return CDbCommand 
  61.      * */ 
  62.     public function createCommand($sql = null) { 
  63.         if ($this->enableSlave && !emptyempty($this->slaves) && is_string($sql) && !$this->getCurrentTransaction() && self::isReadOperation($sql) && ($slave = $this->getSlave()) 
  64.         ) { 
  65.             return $slave->createCommand($sql); 
  66.         } else { 
  67.             if (!$this->masterRead) { 
  68.                 if ($this->_disableWrite && !self::isReadOperation($sql)) { 
  69.  
  70.                     throw new CDbException("Master db server is not available now!Disallow write operation on slave server!"); 
  71.                 } 
  72.             } 
  73.             return parent::createCommand($sql); 
  74.         } 
  75.     } 
  76.  
  77.     /** 
  78.      * 获得从服务器连接资源 
  79.      * @return CDbConnection 
  80.      * */ 
  81.     public function getSlave() { 
  82.         if (!isset($this->_slave)) { 
  83.             shuffle($this->slaves); 
  84.             foreach ($this->slaves as $slaveConfig) { 
  85.                 if ($this->_isDeadServer($slaveConfig['connectionString'])) { 
  86.                     continue
  87.                 } 
  88.                 if (!isset($slaveConfig['class'])) 
  89.                     $slaveConfig['class'] = 'CDbConnection'
  90.  
  91.                 $slaveConfig['autoConnect'] = false; 
  92.                 try { 
  93.                     if ($slave = Yii::createComponent($slaveConfig)) { 
  94.                         Yii::app()->setComponent('dbslave'$slave); 
  95.                         $slave->setAttribute(PDO::ATTR_TIMEOUT, $this->timeout); 
  96.                         $slave->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); 
  97.                         $slave->setActive(true); 
  98.                         $this->_slave = $slave
  99.                         break
  100.                     } 
  101.                 } catch (Exception $e) { 
  102.                     $this->_markDeadServer($slaveConfig['connectionString']); 
  103.                     Yii::log("Slave database connection failed!ntConnection string:{$slaveConfig['connectionString']}"'warning'); 
  104.  
  105.                     continue
  106.                 } 
  107.             } 
  108.  
  109.             if (!isset($this->_slave)) { 
  110.                 $this->_slave = null; 
  111.                 $this->enableSlave = false; 
  112.             } 
  113.         } 
  114.         return $this->_slave; 
  115.     } 
  116.  
  117.     public function setActive($value) { 
  118.         if ($value != $this->getActive()) { 
  119.             if ($value) { 
  120.                 try { 
  121.                     if ($this->_isDeadServer($this->connectionString)) { 
  122.                         throw new CDbException('Master db server is already dead!'); 
  123.                     } 
  124.                     //PDO::ATTR_TIMEOUT must set before pdo instance create 
  125.                     $this->setAttribute(PDO::ATTR_TIMEOUT, $this->timeout); 
  126.                     $this->open(); 
  127.                 } catch (Exception $e) { 
  128.                     $this->_markDeadServer($this->connectionString); 
  129.                     $slave = $this->getSlave(); 
  130.                     Yii::log($e->getMessage(), CLogger::LEVEL_ERROR, 'exception.CDbException'); 
  131.                     if ($slave) { 
  132.                         $this->connectionString = $slave->connectionString; 
  133.                         $this->username = $slave->username; 
  134.                         $this->password = $slave->password; 
  135.                         if ($this->slavesWrite) { 
  136.                             $this->_disableWrite = false; 
  137.                         } 
  138.                         $this->open(); 
  139.                     } else { //Slave also unavailable 
  140.                         if ($this->masterRead) { 
  141.                             $this->connectionString = $this->connectionString; 
  142.                             $this->username = $this->username; 
  143.                             $this->password = $this->password; 
  144.                             $this->open(); 
  145.                         } else { 
  146.                             throw new CDbException(Yii::t('yii''CDbConnection failed to open the DB connection.'), (int) $e->getCode(), $e->errorInfo); 
  147.                         } 
  148.                     } 
  149.                 } 
  150.             } else { 
  151.                 $this->close(); 
  152.             } 
  153.         } 
  154.     } 
  155.  
  156.     /** 
  157.      * 检测读操作 sql 语句 
  158.      *  
  159.      * 关键字: SELECT,DECRIBE,SHOW ... 
  160.      * 写操作:UPDATE,INSERT,DELETE ... 
  161.      * */ 
  162.     public static function isReadOperation($sql) { 
  163.         $sql = substr(ltrim($sql), 0, 10); 
  164.         $sql = str_ireplace(array('SELECT''SHOW''DESCRIBE''PRAGMA'), '^O^'$sql); //^O^,magic smile 
  165.         return strpos($sql'^O^') === 0; 
  166.     } 
  167.  
  168.     /** 
  169.      * 检测从服务器是否被标记 失败. 
  170.      */ 
  171.     private function _isDeadServer($c) { 
  172.         $cache = Yii::app()->{$this->cacheID}; 
  173.         if ($cache && $cache->get('DeadServer::' . $c) == 1) { 
  174.             return true; 
  175.         } 
  176.         return false; 
  177.     } 
  178.  
  179.     /** 
  180.      * 标记失败的slaves. 
  181.      */ 
  182.     private function _markDeadServer($c) { 
  183.         $cache = Yii::app()->{$this->cacheID}; 
  184.         if ($cache) { 
  185.             $cache->set('DeadServer::' . $c, 1, $this->markDeadSeconds); 
  186.         } 
  187.     } 

main.php配置:components 数组中,代码如下:

  1. 'db'=>array
  2.         'class'=>'application.extensions.DbConnectionMan',//扩展路径 
  3.         'connectionString' => 'mysql:host=192.168.1.128;dbname=db_xcpt',//主数据库 写 
  4.         'emulatePrepare' => true, 
  5.         'username' => 'root'
  6.         'password' => 'root'
  7.         'charset' => 'utf8'
  8.         'tablePrefix' => 'xcpt_'//表前缀 
  9.         'enableSlave'=>true,//从数据库启用 
  10.    'urgencyWrite'=>true,//紧急情况 主数据库无法连接 启用从数据库 写功能 
  11.     'masterRead'=>true,//紧急情况 从数据库无法连接 启用主数据库 读功能 
  12.         'slaves'=>array(//从数据库 
  13.             array(   //slave1 
  14.                 'connectionString'=>'mysql:host=localhost;dbname=db_xcpt'
  15.                 'emulatePrepare' => true, 
  16.                 'username'=>'root'
  17.                 'password'=>'root'
  18.                 'charset' => 'utf8'
  19.                 'tablePrefix' => 'xcpt_'//表前缀 
  20.             ), 
  21.    array(   //slave2 
  22.                 'connectionString'=>'mysql:host=localhost;dbname=db_xcpt'
  23.                 'emulatePrepare' => true, 
  24.                 'username'=>'root'
  25.                 'password'=>'root'
  26.                 'charset' => 'utf8'
  27.                 'tablePrefix' => 'xcpt_'//表前缀 
  28.             ), 
  29.  
  30.         ), 
  31. ),

Tags: Yii主从读写分离

分享到: