thinkphp下MySQL数据库读写分离代码剖析


Posted in PHP onApril 18, 2017

当采用原生态的sql语句进行写入操作的时候,要用execute,读操作要用query。

MySQL数据主从同步还是要靠MySQL的机制来实现,所以这个时候MySQL主从同步的延迟问题是需要优化,延迟时间太长不仅影响业务,还影响用户体验。

thinkphp核心类Thinkphp/library/Model.class.php 中,query 方法,调用Thinkphp/library/Think/Db/Driver/Mysql.class.php

/**
   * SQL查询
   * @access public
   * @param string $sql SQL
   * @param mixed $parse 是否需要解析SQL 
   * @return mixed
   */
  public function query($sql,$parse=false) {
    if(!is_bool($parse) && !is_array($parse)) {
      $parse = func_get_args();
      array_shift($parse);
    }
    $sql =  $this->parseSql($sql,$parse);
    return $this->db->query($sql);
  }

调用Thinkphp/library/Think/Db/Driver/Mysql.class.php

/**
   * 执行查询 返回数据集
   * @access public
   * @param string $str sql指令
   * @return mixed
   */
  public function query($str) {
    if(0===stripos($str, 'call')){ // 存储过程查询支持
      $this->close();
      $this->connected  =  false;
    }
    $this->initConnect(false);
    if ( !$this->_linkID ) return false;
    $this->queryStr = $str;
    //释放前次的查询结果
    if ( $this->queryID ) {  $this->free();  }
    N('db_query',1);
    // 记录开始执行时间
    G('queryStartTime');
    $this->queryID = mysql_query($str, $this->_linkID);
    $this->debug();
    if ( false === $this->queryID ) {
      $this->error();
      return false;
    } else {
      $this->numRows = mysql_num_rows($this->queryID);
      return $this->getAll();
    }
  }

上面初始化数据库链接时,initConnect(false),调用Thinkphp/library/Think/Db/Db.class.php,注意false、true代码实现。true表示直接调用主库,false表示调用读写分离的读库。

/**
   * 初始化数据库连接
   * @access protected
   * @param boolean $master 主服务器
   * @return void
   */
  protected function initConnect($master=true) {
    if(1 == C('DB_DEPLOY_TYPE'))
      // 采用分布式数据库
      $this->_linkID = $this->multiConnect($master);
    else
      // 默认单数据库
      if ( !$this->connected ) $this->_linkID = $this->connect();
  }

  /**
   * 连接分布式服务器
   * @access protected
   * @param boolean $master 主服务器
   * @return void
   */
  protected function multiConnect($master=false) {
    foreach ($this->config as $key=>$val){
      $_config[$key]   =  explode(',',$val);
    }    
    // 数据库读写是否分离
    if(C('DB_RW_SEPARATE')){
      // 主从式采用读写分离
      if($master)
        // 主服务器写入
        $r =  floor(mt_rand(0,C('DB_MASTER_NUM')-1));
      else{
        if(is_numeric(C('DB_SLAVE_NO'))) {// 指定服务器读
          $r = C('DB_SLAVE_NO');
        }else{
          // 读操作连接从服务器
          $r = floor(mt_rand(C('DB_MASTER_NUM'),count($_config['hostname'])-1));  // 每次随机连接的数据库
        }
      }
    }else{
      // 读写操作不区分服务器
      $r = floor(mt_rand(0,count($_config['hostname'])-1));  // 每次随机连接的数据库
    }
    $db_config = array(
      'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
      'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
      'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
      'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
      'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
      'dsn'    => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
      'params'  => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0],
      'charset'  => isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],      
    );
    return $this->connect($db_config,$r);
  }

query方法参数为false,其他删除、更新、增加读主库。这一点可以结合Thinkphp/library/Model.class.php中的delete、save、add操作,参数为true。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP+MYSQL 出现乱码的解决方法
Aug 08 PHP
php之对抗Web扫描器的脚本技巧
Oct 01 PHP
php expects parameter 1 to be resource, array given 错误
Mar 23 PHP
PHP Cookie的使用教程详解
Jun 03 PHP
php 判断是否是中文/英文/数字示例代码
Sep 30 PHP
PHP统计目录大小的自定义函数分享
Nov 18 PHP
thinkphp中空模板与空模块的用法实例
Nov 26 PHP
php中namespace及use用法分析
Dec 06 PHP
基于PHP实现的多元线性回归模拟曲线算法
Jan 30 PHP
php获得刚插入数据的id 的几种方法总结
May 31 PHP
thinkPHP5框架实现基于ajax的分页功能示例
Jun 12 PHP
laravel框架中视图的基本使用方法分析
Nov 23 PHP
Thinkphp通过一个入口文件如何区分移动端和PC端
Apr 18 #PHP
Yii2汉字转拼音类的实例代码
Apr 18 #PHP
php+resumablejs实现的分块上传 断点续传功能示例
Apr 18 #PHP
ZendFramework2连接数据库操作实例
Apr 18 #PHP
PHP实现的数独求解问题示例
Apr 18 #PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
Apr 18 #PHP
php实现不通过扩展名准确判断文件类型的方法【finfo_file方法与二进制流】
Apr 18 #PHP
You might like
PHP n个不重复的随机数生成代码
2009/06/23 PHP
php 过滤器实现代码
2010/08/09 PHP
PHP程序员必须清楚的问题汇总
2014/12/18 PHP
分享一个我自己写的ToolTip提示插件(附源码)
2013/01/20 Javascript
JavaScript中的对象的extensible属性介绍
2014/12/30 Javascript
Javascript中获取对象的原型对象的方法小结
2015/02/25 Javascript
基于JQuery的$.ajax方法进行异步请求导致页面闪烁的解决办法
2016/05/10 Javascript
jQuery实现ToolTip元素定位显示功能示例
2016/11/23 Javascript
jquery滚动条插件(可以自定义)
2016/12/11 Javascript
详解闭包解决jQuery中AJAX的外部变量问题
2017/02/22 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
从零开始学习Node.js系列教程之设置HTTP头的方法示例
2017/04/13 Javascript
详解vue2父组件传递props异步数据到子组件的问题
2017/06/29 Javascript
使用InstantClick.js让页面提前加载200ms
2017/09/12 Javascript
vue2.0 datepicker使用方法
2018/02/04 Javascript
node puppeteer(headless chrome)实现网站登录
2018/05/09 Javascript
在Vue组件中获取全局的点击事件方法
2018/09/06 Javascript
基于axios 解决跨域cookie丢失的问题
2018/09/26 Javascript
Javascript 模拟mvc实现点餐程序案例详解
2020/12/24 Javascript
[04:10]DOTA2英雄梦之声_第11期_圣堂刺客
2014/06/21 DOTA
Python argv用法详解
2016/01/08 Python
Python的socket模块源码中的一些实现要点分析
2016/06/06 Python
对python使用telnet实现弱密码登录的方法详解
2019/01/26 Python
python如何调用java类
2020/07/05 Python
Python3基于plotly模块保存图片表格
2020/08/03 Python
CSS3图片旋转特效(360/60/-360度)
2013/10/10 HTML / CSS
阿迪达斯墨西哥官方网站:adidas墨西哥
2017/11/03 全球购物
物流管理应届生求职信
2013/11/07 职场文书
集团公司党的群众路线教育实践活动工作总结
2014/03/03 职场文书
消防志愿者活动方案
2014/08/23 职场文书
党员批评与自我批评(5篇)
2014/09/23 职场文书
《雷雨》教学反思
2016/02/20 职场文书
赞美教师的句子
2019/09/02 职场文书
Java SSH 秘钥连接mysql数据库的方法
2021/06/28 Java/Android
postman中form-data、x-www-form-urlencoded、raw、binary的区别介绍
2022/01/18 HTML / CSS
解决persistence.xml配置文件修改存放路径的问题
2022/02/24 Java/Android