php实现带读写分离功能的MySQL类完整实例


Posted in PHP onJuly 28, 2016

本文实例讲述了php实现带读写分离功能的MySQL类。分享给大家供大家参考,具体如下:

概述:

1. 根据sql语句判断是连接读库还是写库
2. 链式调用$this->where()->get()
3. 不同的主机对应不同的实例, 不再多次new

具体代码如下:

<?php
class DBRWmysql
{
  private static $Instance = null;
  private $links = array();//链接数组
  private $link = null; //当前连接
  public $dbType = 'read';
  public $_host=''; //数据库所在主机名
  public $_database = '';//当前数据库名
  public $_tablename = '';//当前表的表名
  public $_dt ='';//database.tablename
  public $isRelease = 0; //查询完成后是否释放
  public $fields = '*';
  public $arrWhere = [];
  public $order = '';
  public $arrOrder = [];
  public $limit = '';
  public $sql = '';
  public $rs;//结果集
  private function __construct($database='', $tablename='', $isRelease=0)
  {
    $this->_database = $database;//database name
    $this->_tablename = $tablename;//table name
    $this->_dt = "`{$this->_database}`.`{$this->_tablename}`";
    $this->isRelease = $isRelease;
  }
  public static function getInstance($database='', $tablename='', $isRelease=0)
  {
    if (self::$Instance == null) {
      self::$Instance = new DBRWmysql($database, $tablename, $isRelease);
    }
    self::$Instance->_database = $database;
    self::$Instance->_tablename = $tablename;
    self::$Instance->_dt    = "`{$database}`.`{$tablename}`";
    self::$Instance->isRelease = $isRelease;
    return self::$Instance;
  }
  //如果主机没变,并且已经存在MYSQL连接,就不再创建新的连接
  //如果主机改变,就再生成一个实例创建一个连接
  //type == 'write'或'read'
  public function getLink($type)
  {
    $this->dbType = $$type;
    //随机选取一个数据库连接(区分读写)
    $dbConfig = DBConfig::$$type;
    $randKey = array_rand($dbConfig);
    $config = $dbConfig[$randKey];
    //链接数据库
    $host = $config['host'];
    $username = $config['username'];
    $password = $config['password'];
    if (empty($this->links[$host])) {
      $this->_host = $host;
      $this->links[$host] = new mysqli($host, $username, $password);
      if($this->links[$host]->connect_error) {
        $this->error($this->links[$host]->connect_error);
      }
    }
    //初始化链接
    $this->link = $this->links[$host];
    $this->link->query("set names utf8mb4;"); //支持emoji表情
    $this->link->query("use {$this->_database};");
  }
  public function getCurrentLinks()
  {
    return $this->links;
  }
  //析构函数
  public function __destruct()
  {
    foreach ($this->links as $v) {
      $v->close();
    }
  }
  //查询封装
  public function query($sql)
  {
    $this->sql = $sql;
    if (strpos($sql, 'select') !== false) {
      $this->getLink('read');//读库
    } else {
      $this->getLink('write');//写库
    }
    $this->rs = $this->link->query($sql);
    ($this->rs === false) && $this->error('sql error: '.$sql.PHP_EOL.$this->link->error);
    //查询完成后释放链接, 并删除链接对象
    if ($this->isRelease) {
      $this->link->close();
      unset($this->links[$this->_host]);
    }
    return $this->rs;
  }
  //增
  public function insert($arrData)
  {
    foreach ($arrData as $key=>$value) {
      $fields[] = $key;
      $values[] = "'".$value."'";
      // $fields[] = '`'.$key.'`';
      // $values[] = "'".$value."'";
    }
    $strFields = implode(',', $fields);
    $strValues = implode(',', $values);
    $sql = "insert into {$this->_dt} ($strFields) values ($strValues)";
    $this->query($sql);
    $insert_id = $this->link->insert_id;
    return $insert_id;
  }
  //增
  public function replace($arrData)
  {
    foreach ($arrData as $key=>$value) {
      $fields[] = $key;
      $values[] = "'{$value}'";
    }
    $strFields = implode(',', $fields);
    $strValues = implode(',', $values);
    $sql = "replace into {$this->_dt} ($strFields) values ($strValues)";
    $this->query($sql);
    return $this->link->insert_id;
  }
  //增
  //每次插入多条记录
  //每条记录的字段相同,但是值不一样
  public function insertm($arrFields, $arrData)
  {
    foreach ($arrFields as $v) {
      // $fields[] = "`{$v}`";
      $fields[] = $v;
    }
    foreach ($arrData as $v) {
      $data[] = '('.implode(',', $v).')';
    }
    $strFields = implode(',', $fields);
    $strData = implode(',', $data);
    $sql = "insert into {$this->_dt} ($strFields) values {$strData}";
    $this->query($sql);
    return $this->link->insert_id;
  }
  //删
  public function delete()
  {
    $where = $this->getWhere();
    $limit = $this->getLimit();
    $sql = " delete from {$this->_dt} {$where} {$limit}";
    $this->query($sql);
    return $this->link->affected_rows;
  }
  //改
  public function update($data)
  {
    $where = $this->getWhere();
    $arrSql = array();
    foreach ($data as $key=>$value) {
      $arrSql[] = "{$key}='{$value}'";
    }
    $strSql = implode(',', $arrSql);
    $sql = "update {$this->_dt} set {$strSql} {$where} {$this->limit}";
    $this->query($sql);
    return $this->link->affected_rows;
  }
  //获取总数
  public function getCount()
  {
    $where = $this->getWhere();
    $sql = " select count(1) as n from {$this->_dt} {$where} ";
    $resault = $this->query($sql);
    ($resault===false) && $this->error('getCount error: '.$sql);
    $arrRs = $this->rsToArray($resault);
    $num = array_shift($arrRs);
    return $num['n'];
  }
  //将结果集转换成数组返回
  //如果field不为空,则返回的数组以$field为键重新索引
  public function rsToArray($field = '')
  {
    $arrRs = $this->rs->fetch_all(MYSQLI_ASSOC); //该函数只能用于php的mysqlnd驱动
    $this->rs->free();//释放结果集
    if ($field) {
      $arrResult = [];
      foreach ($arrRs as $v) {
        $arrResult[$v[$field]] = $v;
      }
      return $arrResult;
    }
    return $arrRs;
  }
  //给字段名加上反引号
  public function qw($strFields)
  {
    $strFields = preg_replace('#\s+#', ' ', $strFields);
    $arrNewFields = explode(' ', $strFields );
    $arrNewFields = array_filter($arrNewFields);
    foreach ($arrNewFields as $k => $v) {
      $arrNewFields[$k]= '`'.$v.'`';
    }
    return implode(',', $arrNewFields);
  }
  //处理入库数据,将字符串格式的数据转换为...格式(未实现)
  public function getInsertData($strData)
  {
    // $bmap = "jingdu,$jingdu weidu,$weidu content,$content";
  }
  //select in
  //arrData 整数数组,最好是整数
  public function select_in($key, $arrData, $fields='')
  {
    $fields = $fields ? $fields : '*';
    sort($arrData);
    $len = count($arrData);
    $cur = 0;
    $pre = $arrData[0];
    $new = array('0' => array($arrData[0]));
    for ($i = 1; $i < $len; $i++) {
      if (($arrData[$i] - $pre) == 1 ) {
        $new[$cur][] = $arrData[$i];
      } else {
        $cur = $i;
        $new[$cur][] = $arrData[$i];
      }
      $pre = $arrData[$i];
    }
    $arrSql = array();
    foreach ($new as $v) {
      $len = count($v) - 1;
      if ($len) {
        $s = $v[0];
        $e = end($v);
        $sql = "(select $fields from {$this->_dt} where $key between $s and $e)";
      } else {
        $s = $v[0];
        $sql = "(select $fields from {$this->_dt} where $key = $s)";
      }
      $arrSql[] = $sql;
    }
    $strUnion = implode(' UNION ALL ', $arrSql);
    $res = $this->query($strUnion);
    return $this->rstoarray($res);
  }
  //where in
  public function setWhereIn($key, $arrData)
  {
    if (empty($arrData)) {
      $str = "(`{$key}` in ('0'))";
      $this->addWhere($str);
      return $str;
    }
    foreach ($arrData as &$v) {
      $v = "'{$v}'";
    }
    $str = implode(',', $arrData);
    $str = "(`{$key}` in ( {$str} ))";
    $this->addWhere($str);
    return $this;
  }
  //where in
  public function setWhere($arrData)
  {
    if (empty($arrData)) {
      return '';
    }
    foreach ($arrData as $k => $v) {
      $str = "(`{$k}` = '{$v}')";
      $this->addWhere($str);
    }
    return $this;
  }
  //between and
  public function setWhereBetween($key, $min, $max)
  {
    $str = "(`{$key}` between '{$min}' and '{$max}')";
    $this->addWhere($str);
    return $this;
  }
  //where a>b
  public function setWhereBT($key, $value)
  {
    $str = "(`{$key}` > '{$value}')";
    $this->addWhere($str);
    return $this;
  }
  //where a<b
  public function setWhereLT($key, $value)
  {
    $str = "(`{$key}` < '{$value}')";
    $this->addWhere($str);
    return $this;
  }
  //组装where条件
  public function addWhere($where)
  {
    $this->arrWhere[] = $where;
  }
  //获取最终查询用的where条件
  public function getWhere()
  {
    if (empty($this->arrWhere)) {
      return 'where 1';
    } else {
      return 'where '.implode(' and ', $this->arrWhere);
    }
  }
  //以逗号隔开
  public function setFields($fields)
  {
    $this->fields = $fields;
    return $this;
  }
  // order by a desc
  public function setOrder($order)
  {
    $this->arrOrder[] = $order;
    return $this;
  }
  //获取order语句
  public function getOrder()
  {
    if (empty($this->arrOrder)) {
      return '';
    } else {
      $str = implode(',', $this->arrOrder);
      $this->order = "order by {$str}";
    }
    return $this->order;
  }
  //e.g. '0, 10'
  //用limit的时候可以加where条件优化:select ... where id > 1234 limit 0, 10
  public function setLimit($limit)
  {
    $this->limit = 'limit '.$limit;
    return $this;
  }
  //直接查询sql语句, 返回数组格式
  public function arrQuery($sql, $field='')
  {
    $this->query($sql);
    $this->clearQuery();
    ($this->rs===false) && $this->error('select error: '.$sql);
    return $this->rsToArray($field);
  }
  //如果 $field 不为空, 则返回的结果以该字段的值为索引
  //暂不支持join
  public function get($field='')
  {
    $where = $this->getWhere();
    $order = $this->getOrder();
    $sql = " select {$this->fields} from {$this->_dt} {$where} {$order} {$this->limit} ";
    return $this->arrQuery($sql, $field);
  }
  //获取一条记录
  public function getOne()
  {
    $this->setLimit(1);
    $rs = $this->get();
    return !empty($rs) ? $rs[0] : [];
  }
  //获取一条记录的某一个字段的值
  public function getOneField($field)
  {
    $this->setFields($field);
    $rs = $this->getOne();
    return !empty($rs[$field]) ? $rs[$field] : '';
  }
  //获取数据集中所有某个字段的值
  public function getFields($field)
  {
    $this->setFields($field);
    $rs = $this->get();
    $result = [];
    foreach ($rs as $v) {
      $result[] = $v[$field];
    }
    unset($rs);
    return $result;
  }
  //清除查询条件
  //防止干扰下次查询
  public function clearQuery()
  {
    $this->fields = '*';
    $this->arrWhere = [];
    $this->order = '';
    $this->arrOrder = [];
    $this->limit = '';
  }
  //断开数据库连接
  public function close()
  {
    $this->link->close();
  }
  //事务
  //自动提交开关
  public function autocommit($bool)
  {
    $this->link->autocommit($bool);
  }
  //事务完成提交
  public function commit()
  {
    $this->link->commit();
  }
  //回滚
  public function rollback()
  {
    $this->link->rollback();
  }
  //输出错误sql语句
  public function error($sql)
  {
    //if (IS_TEST) {}
    exit($sql);
  }
}

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP4实际应用经验篇(8)
Oct 09 PHP
PHP 函数语法介绍一
Jun 14 PHP
smarty中先strip_tags过滤html标签后truncate截取文章运用
Oct 25 PHP
php iconv() : Detected an illegal character in input string
Dec 05 PHP
php curl 登录163邮箱并抓取邮箱好友列表的代码(经测试)
Apr 07 PHP
php全角字符转换为半角函数
Feb 07 PHP
php修改文件上传限制方法汇总
Apr 07 PHP
标准版Eclipse搭建PHP环境的详细步骤
Nov 18 PHP
PHP中header用法小结
May 23 PHP
Yii模型操作之criteria查找数据库的方法
Jul 15 PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
Apr 20 PHP
PHP count_chars()函数讲解
Feb 14 PHP
PHP实现带重试功能的curl连接示例
Jul 28 #PHP
php使用strip_tags()去除html标签仍有空白的解决方法
Jul 28 #PHP
php倒计时出现-0情况的解决方法
Jul 28 #PHP
24条货真价实的PHP代码优化技巧
Jul 28 #PHP
php求今天、昨天、明天时间戳的简单实现方法
Jul 28 #PHP
php字符串操作针对负值的判断分析
Jul 28 #PHP
PHP实现bitmap位图排序与求交集的方法
Jul 28 #PHP
You might like
php设计模式 Mediator (中介者模式)
2011/06/26 PHP
php实现zip文件解压操作
2015/11/03 PHP
php  单例模式详细介绍及实现源码
2016/11/05 PHP
PHP 图片合成、仿微信群头像的方法示例
2019/10/25 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
jQuery 和 CSS 的文本特效插件集锦
2014/12/12 Javascript
javascript 数组操作详解
2015/01/29 Javascript
js闭包所用的场合以及优缺点分析
2015/06/22 Javascript
Javascript验证方法大全
2015/09/21 Javascript
基于javascript实现文字无缝滚动效果
2016/03/22 Javascript
深入理解Angular4中的依赖注入
2017/06/07 Javascript
JS检测是否可以访问公网服务器功能代码
2017/06/19 Javascript
vue动态注册组件实例代码详解
2019/05/30 Javascript
NodeJs 实现简单WebSocket即时通讯的示例代码
2019/08/05 NodeJs
微信小程序授权登陆及每次检查是否授权实例代码
2019/09/18 Javascript
[41:08]2014 DOTA2国际邀请赛中国区预选赛 HGT VS NE
2014/05/22 DOTA
[05:39]2014DOTA2国际邀请赛 DK晋级胜者组专访战队国士无双
2014/07/14 DOTA
python使用paramiko实现远程拷贝文件的方法
2016/04/18 Python
Python正则替换字符串函数re.sub用法示例
2017/01/19 Python
Python编程实现输入某年某月某日计算出这一天是该年第几天的方法
2017/04/18 Python
Python中类的初始化特殊方法
2017/12/01 Python
详解python中的Turtle函数库
2018/11/19 Python
Python3使用xml.dom.minidom和xml.etree模块儿解析xml文件封装函数的方法
2019/09/23 Python
python实现逆滤波与维纳滤波示例
2020/02/26 Python
关于box-sizing的全面理解
2016/07/28 HTML / CSS
利用CSS3实现文字折纸效果实例代码
2018/07/10 HTML / CSS
html5-websocket基于远程方法调用的数据交互实现
2012/12/04 HTML / CSS
乐高奥地利官方商店:LEGO Shop AT
2019/07/16 全球购物
T3官网:头发造型工具
2019/12/26 全球购物
保安员岗位职责
2013/11/17 职场文书
法学专业本科生自荐信范文
2013/12/17 职场文书
办公室前台岗位职责
2014/01/04 职场文书
学生党员思想汇报范文
2014/01/09 职场文书
财务内勤岗位职责
2014/04/17 职场文书
干部鉴定材料
2014/05/18 职场文书
办公室岗位职责范本
2015/04/11 职场文书