读写分离MYSQL类

2014年4月27日 12:34:08

概述:

1. 根据sql语句判断是连接读库还是写库

2. 链式调用$this->where()->get()

3. 不同的主机对应不同的实例, 不再多次new

  1 <?php
  2 class DBRWmysql
  3 {
  4     private static $Instance = null;
  5 
  6     private $links = array();//链接数组
  7     private $link = null; //当前连接
  8     public $dbType = 'read';
  9 
 10     public $_host=''; //数据库所在主机名
 11     public $_database = '';//当前数据库名
 12     public $_tablename = '';//当前表的表名
 13     public $_dt ='';//database.tablename
 14     public $isRelease = 0; //查询完成后是否释放
 15 
 16     public $fields = '*';
 17     public $arrWhere = [];
 18     public $order = '';
 19     public $arrOrder = [];
 20     public $limit = '';
 21     public $sql = '';
 22 
 23     public $rs;//结果集
 24 
 25     private function __construct($database='', $tablename='', $isRelease=0)
 26     {
 27         $this->_database = $database;//database name
 28         $this->_tablename = $tablename;//table name
 29         $this->_dt = "`{$this->_database}`.`{$this->_tablename}`";
 30         $this->isRelease = $isRelease;
 31     }
 32 
 33     public static function getInstance($database='', $tablename='', $isRelease=0)
 34     {
 35         if (self::$Instance == null) {
 36             self::$Instance = new DBRWmysql($database, $tablename, $isRelease);
 37         }
 38 
 39         self::$Instance->_database  = $database;
 40         self::$Instance->_tablename = $tablename;
 41         self::$Instance->_dt        = "`{$database}`.`{$tablename}`";
 42         self::$Instance->isRelease  = $isRelease;
 43 
 44         return self::$Instance;
 45     }
 46 
 47     //如果主机没变,并且已经存在MYSQL连接,就不再创建新的连接
 48     //如果主机改变,就再生成一个实例创建一个连接
 49     //type == 'write'或'read'
 50     public function getLink($type)
 51     {
 52         $this->dbType = $$type;
 53 
 54         //随机选取一个数据库连接(区分读写)
 55         $dbConfig = DBConfig::$$type;
 56         $randKey = array_rand($dbConfig);
 57         $config = $dbConfig[$randKey];
 58 
 59         //链接数据库
 60         $host = $config['host'];
 61         $username = $config['username'];
 62         $password = $config['password'];
 63 
 64         if (empty($this->links[$host])) {
 65             $this->_host = $host;
 66             $this->links[$host] = new mysqli($host, $username, $password);
 67             if($this->links[$host]->connect_error) {
 68                 $this->error($this->links[$host]->connect_error);
 69             }
 70         }
 71 
 72         //初始化链接
 73         $this->link = $this->links[$host];
 74         $this->link->query("set names utf8mb4;"); //支持emoji表情
 75         $this->link->query("use {$this->_database};");
 76     }
 77     
 78     public function getCurrentLinks()
 79     {
 80         return $this->links;
 81     }
 82     
 83     //析构函数
 84     public function __destruct()
 85     {
 86         foreach ($this->links as $v) {
 87             $v->close();
 88         }
 89     }
 90     
 91     //查询封装
 92     public function query($sql)
 93     {
 94         $this->sql = $sql;
 95         if (strpos($sql, 'select') !== false) {
 96             $this->getLink('read');//读库
 97         } else {
 98             $this->getLink('write');//写库
 99         }
100 
101         $this->rs = $this->link->query($sql);
102         ($this->rs === false) && $this->error('sql error: '.$sql.PHP_EOL.$this->link->error);
103 
104         //查询完成后释放链接, 并删除链接对象
105         if ($this->isRelease) {
106             $this->link->close();
107             unset($this->links[$this->_host]);
108         }
109         return $this->rs;
110     }
111     
112 
113     //
114     public function insert($arrData)
115     {
116         foreach ($arrData as $key=>$value) {
117             $fields[] = $key;
118             $values[] = "'".$value."'";
119             // $fields[] = '`'.$key.'`';
120             // $values[] = "'".$value."'";
121         }
122         $strFields = implode(',', $fields);
123         $strValues = implode(',', $values);
124         $sql = "insert into {$this->_dt} ($strFields) values ($strValues)";
125         $this->query($sql);
126         $insert_id = $this->link->insert_id;
127         
128         return $insert_id;
129     }
130 
131     //
132     public function replace($arrData)
133     {
134         foreach ($arrData as $key=>$value) {
135             $fields[] = $key;
136             $values[] = "'{$value}'";
137         }
138         $strFields = implode(',', $fields);
139         $strValues = implode(',', $values);
140         $sql = "replace into {$this->_dt} ($strFields) values ($strValues)";
141         
142         $this->query($sql);
143         
144         return $this->link->insert_id;
145     }
146     
147     //148     //每次插入多条记录
149     //每条记录的字段相同,但是值不一样
150     public function insertm($arrFields, $arrData)
151     {
152         foreach ($arrFields as $v) {
153             // $fields[] = "`{$v}`";
154             $fields[] = $v;
155         }
156         
157         foreach ($arrData as $v) {
158             $data[] = '('.implode(',', $v).')';
159         }
160         
161         $strFields = implode(',', $fields);
162         $strData = implode(',', $data);
163         
164         $sql = "insert into {$this->_dt} ($strFields) values {$strData}";
165         
166         $this->query($sql);
167         
168         return $this->link->insert_id;
169     }
170     
171     //
172     public function delete()
173     {
174         $where = $this->getWhere();
175         $limit = $this->getLimit();
176 
177         $sql = " delete from {$this->_dt} {$where} {$limit}";
178         $this->query($sql);
179         return $this->link->affected_rows;
180     }
181     
182     //
183     public function update($data)
184     {
185         $where = $this->getWhere();
186 
187         $arrSql = array();
188         foreach ($data as $key=>$value) {
189             $arrSql[] = "{$key}='{$value}'";
190         }
191         $strSql = implode(',', $arrSql);
192         
193         $sql = "update {$this->_dt} set {$strSql} {$where} {$this->limit}";
194         
195         $this->query($sql);
196         
197         return $this->link->affected_rows;
198     
199     }
200 
201     //获取总数
202     public function getCount()
203     {
204         $where = $this->getWhere();
205         
206         $sql = " select count(1) as n from {$this->_dt} {$where} ";
207         $resault = $this->query($sql);
208         
209         ($resault===false) && $this->error('getCount error: '.$sql);
210         
211         $arrRs = $this->rsToArray($resault);
212         
213         $num = array_shift($arrRs);
214         return $num['n'];
215     }
216     
217     //将结果集转换成数组返回
218     //如果field不为空,则返回的数组以$field为键重新索引
219     public function rsToArray($field = '')
220     {
221         $arrRs = $this->rs->fetch_all(MYSQLI_ASSOC); //该函数只能用于php的mysqlnd驱动
222         $this->rs->free();//释放结果集
223         
224         if ($field) {
225             $arrResult = [];
226             foreach ($arrRs as $v) {
227                 $arrResult[$v[$field]] = $v;
228             }
229             return $arrResult;
230         }
231         
232         return $arrRs;
233     }
234     
235     //给字段名加上反引号
236     public function qw($strFields)
237     {
238         $strFields = preg_replace('#\s+#', ' ', $strFields);
239         $arrNewFields = explode(' ', $strFields );
240         $arrNewFields = array_filter($arrNewFields);
241         foreach ($arrNewFields as $k => $v) {
242             $arrNewFields[$k]= '`'.$v.'`';
243         }
244         return implode(',', $arrNewFields);
245     }
246 
247     //处理入库数据,将字符串格式的数据转换为...格式(未实现)
248     public function getInsertData($strData)
249     {
250         // $bmap = "jingdu,$jingdu weidu,$weidu content,$content";
251     }
252 
253     //select in
254     //arrData 整数数组,最好是整数
255     public function select_in($key, $arrData, $fields='')
256     {
257         $fields = $fields ? $fields : '*';
258         sort($arrData);
259         $len = count($arrData);
260         $cur = 0;
261         $pre = $arrData[0];
262 
263         $new = array('0' => array($arrData[0]));
264         for ($i = 1; $i < $len; $i++) {
265             if (($arrData[$i] - $pre) == 1 ) {
266                 $new[$cur][] = $arrData[$i];
267             } else {
268                 $cur = $i;
269                 $new[$cur][] = $arrData[$i];
270             }
271             $pre = $arrData[$i];
272         }
273 
274         $arrSql = array();
275         foreach ($new as $v) {
276             $len = count($v) - 1;
277             if ($len) {
278                 $s = $v[0];
279                 $e = end($v);
280                 $sql = "(select $fields from {$this->_dt} where $key between $s and $e)";
281             } else {
282                 $s = $v[0];
283                 $sql = "(select $fields from {$this->_dt} where $key = $s)";
284             }
285 
286             $arrSql[] = $sql;
287         }
288         
289         $strUnion = implode(' UNION ALL ', $arrSql);
290         $res = $this->query($strUnion);
291         return $this->rstoarray($res);
292     }
293     
294     //where in
295     public function setWhereIn($key, $arrData)
296     {
297         if (empty($arrData)) {
298             $str = "(`{$key}` in ('0'))";
299             $this->addWhere($str);
300             return $str;
301         }
302         
303         foreach ($arrData as &$v) {
304             $v = "'{$v}'";
305         }
306         $str = implode(',', $arrData);
307         $str = "(`{$key}` in ( {$str} ))";
308         
309         $this->addWhere($str);
310         
311         return $this;
312     }
313     
314     //where in
315     public function setWhere($arrData)
316     {
317         if (empty($arrData)) {
318             return '';
319         }
320         
321         foreach ($arrData as $k => $v) {
322             $str = "(`{$k}` = '{$v}')";
323             $this->addWhere($str);
324         }
325         
326         return $this;
327     }
328     
329     //between and
330     public function setWhereBetween($key, $min, $max)
331     {
332         $str = "(`{$key}` between '{$min}' and '{$max}')";
333         $this->addWhere($str);
334         return $this;
335     }
336     
337     //where a>b
338     public function setWhereBT($key, $value)
339     {
340         $str = "(`{$key}` > '{$value}')";
341         $this->addWhere($str);
342         return $this;
343     }
344     
345     //where a<b
346     public function setWhereLT($key, $value)
347     {
348         $str = "(`{$key}` < '{$value}')";
349         $this->addWhere($str);
350         return $this;
351     }
352     
353     //组装where条件
354     public function addWhere($where)
355     {
356         $this->arrWhere[] = $where;
357     }
358     
359     //获取最终查询用的where条件
360     public function getWhere()
361     {
362         if (empty($this->arrWhere)) {
363             return 'where 1';
364         } else {
365             return 'where '.implode(' and ', $this->arrWhere);
366         }
367     }
368     
369     //以逗号隔开
370     public function setFields($fields)
371     {
372         $this->fields = $fields;
373         return $this;
374     }
375     
376     // order by a desc
377     public function setOrder($order)
378     {
379         $this->arrOrder[] = $order;
380         return $this;
381     }
382     
383     //获取order语句
384     public function getOrder()
385     {
386         if (empty($this->arrOrder)) {
387             return '';
388         } else {
389             $str = implode(',', $this->arrOrder);
390             $this->order = "order by {$str}";
391         }
392         return $this->order;
393     }
394     
395     //e.g. '0, 10'
396     //用limit的时候可以加where条件优化:select ... where id > 1234 limit 0, 10 
397     public function setLimit($limit)
398     {
399         $this->limit = 'limit '.$limit;
400         return $this;
401     }
402 
403     //直接查询sql语句, 返回数组格式
404     public function arrQuery($sql, $field='')
405     {
406         $this->query($sql);
407         $this->clearQuery();
408         ($this->rs===false) && $this->error('select error: '.$sql);
409         return $this->rsToArray($field);
410     }
411     
412     //如果 $field 不为空, 则返回的结果以该字段的值为索引
413     //暂不支持join
414     public function get($field='')
415     {
416         $where = $this->getWhere();
417         $order = $this->getOrder();
418         
419         $sql = " select {$this->fields} from {$this->_dt} {$where} {$order} {$this->limit} ";
420         return $this->arrQuery($sql, $field);
421     }
422     
423     //获取一条记录
424     public function getOne()
425     {
426         $this->setLimit(1);
427         $rs = $this->get();
428 
429         return !empty($rs) ? $rs[0] : [];
430     }
431     
432     //获取一条记录的某一个字段的值
433     public function getOneField($field)
434     {
435         $this->setFields($field);
436         $rs = $this->getOne();
437 
438         return !empty($rs[$field]) ? $rs[$field] : '';
439     }
440 
441     //获取数据集中所有某个字段的值
442     public function getFields($field)
443     {
444         $this->setFields($field);
445         $rs = $this->get();
446         $result = [];
447         foreach ($rs as $v) {
448             $result[] = $v[$field];
449         }
450         unset($rs);
451 
452         return $result;
453     }
454     
455     //清除查询条件
456     //防止干扰下次查询
457     public function clearQuery()
458     {
459         $this->fields = '*';
460         $this->arrWhere = [];
461         $this->order = '';
462         $this->arrOrder = [];
463         $this->limit = '';
464     }
465 
466     //断开数据库连接
467     public function close()
468     {
469         $this->link->close();
470     }
471 
472     //事务
473     //自动提交开关
474     public function autocommit($bool)
475     {
476         $this->link->autocommit($bool);
477     }
478 
479     //事务完成提交
480     public function commit()
481     {
482         $this->link->commit();
483     }
484 
485     //回滚
486     public function rollback()
487     {
488         $this->link->rollback();
489     }
490 
491 
492     //输出错误sql语句
493     public function error($sql)
494     {
495         //if (IS_TEST) {}
496         exit($sql);
497     }
498 }

最后编辑: 2016年4月16日 19:45:14 星期六

posted @ 2014-04-27 12:35  myD  阅读(596)  评论(0编辑  收藏  举报