這是關於 Swoole 入門學習的第八篇文章:Swoole MySQL 鏈接池的實現。php
收到讀者的諮詢,這狀況你們可能也會有,因此就在這說說:html
「亮哥,我今年30歲了,有點中年危機,最近有點焦慮,發現工做雖然很忙,可是沒感受能力有所提高,成天都有寫不完的業務代碼,時間緊有時代碼質量也不怎麼樣,知道還有不少改進空間,但一直沒時間改,主要是後面項目壓着,立刻又要進入開發了,這種狀況怎麼辦?」mysql
首先,我是菜雞,觀點不喜勿噴,那我就說下本身的見解:git
上面的描述比較主觀,人呀有時候發現不了本身的能力很正常,有時候有能力了並非立刻就能顯現的,而是到了某個階段後忽然發現,哇塞,原來本身這麼厲害。github
固然能力也分不少種,好比專業能力,快速學習能力,進度把控能力,還有自信也是一種能力,不要臉是一種能力,堅持不要臉更是一種能力。sql
其實能力提高最快的仍是靠工做實踐,悄悄問問本身加入了不少大牛的微信羣,能力提高了嗎?看書自學不實踐是否是吸取的也很少。數據庫
若是非要給一個具體的方案,那就是在團隊內多分享吧,由於在分享前你會作充分的準備來避免分享時出醜,即便有時候本身知道,當講出來的時候就不是那麼回事了。json
前期分享能夠是看稿,後期練習無稿分享。segmentfault
而後,再多說一點,30了給本身一個目標,不要盲目天天就是學學學,好比目標是技術專家,目標是業務專家,都很好呀,固然目標與本身性格有關也不是一成不變的。緩存
圍繞着目標設置一些計劃,不要覺得天天的學學學,就以爲其餘的一切就天然而來,其中還有不少機遇和人脈的因素。
最後,若是實在感受壓得喘不過氣,就換個環境吧,別和本身過不去。
開始今天的文章,這篇文章實現了 Swoole MySQL 鏈接池,代碼是在《Swoole RPC 的實現》文章的基礎上進行開發的。
先回顧上篇文章的內容:
本篇文章主要的功能點:
<?php if (!defined('SERVER_PATH')) exit("No Access"); class Order { public function get_list($uid = 0, $type = 0) { //TODO 業務代碼 $rs[0]['order_code'] = '1'; $rs[0]['order_name'] = '訂單1'; $rs[1]['order_code'] = '2'; $rs[1]['order_name'] = '訂單2'; $rs[2]['order_code'] = '3'; $rs[2]['order_name'] = '訂單3'; return $rs; } } 修改爲: class Order { private $mysql; private $table; public function __construct() { $pool = MysqlPool::getInstance(); $this->mysql = $pool->get(); $this->table = 'order'; } public function add($code = '', $name = '') { //TODO 驗證 return $this->mysql->insert($this->table, ['code' => $code, 'name' => $name]); } public function edit($id = 0, $name='') { //TODO 驗證 return $this->mysql->update($this->table, ['name' => $name], ['id' => $id]); } public function del($id = 0) { //TODO 驗證 return $this->mysql->delete($this->table, ['id' => $id]); } public function info($code = '') { //TODO 驗證 return $this->mysql->select($this->table, ['code' => $code]); } }
1、須要新增兩項配置:
enable_coroutine = true task_enable_coroutine = true
2、回調參數發生改變
$serv->on('Task', function ($serv, $task_id, $src_worker_id, $data) { ... }); 修改爲: $serv->on('Task', function ($serv, $task) { $task->worker_id; //來自哪一個`Worker`進程 $task->id; //任務的編號 $task->data; //任務的數據 });
Mysql.php
<?php if (!defined('SERVER_PATH')) exit("No Access"); $db['default']['pool_size'] = 3; //鏈接池個數 $db['default']['pool_get_timeout'] = 0.5; //獲取鏈接池超時時間 $db['default']['timeout'] = 0.5; //數據庫創建鏈接超時時間 $db['default']['charset'] = 'utf8'; //字符集 $db['default']['strict_type'] = false; //開啓嚴格模式 $db['default']['fetch_mode'] = true; //開啓fetch模式 $config['master'] = $db['default']; $config['master']['host'] = '127.0.0.1'; $config['master']['port'] = 3306; $config['master']['user'] = 'root'; $config['master']['password'] = '123456'; $config['master']['database'] = 'demo'; $config['slave'] = $db['default']; $config['slave']['host'] = '127.0.0.1'; $config['slave']['port'] = 3306; $config['slave']['user'] = 'root'; $config['slave']['password'] = '123456'; $config['slave']['database'] = 'demo';
MysqlPool.php
<?php if (!defined('SERVER_PATH')) exit("No Access"); class MysqlPool { private static $instance; private $pool; private $config; public static function getInstance($config = null) { if (empty(self::$instance)) { if (empty($config)) { throw new RuntimeException("MySQL config empty"); } self::$instance = new static($config); } return self::$instance; } public function __construct($config) { if (empty($this->pool)) { $this->config = $config; $this->pool = new chan($config['master']['pool_size']); for ($i = 0; $i < $config['master']['pool_size']; $i++) { go(function() use ($config) { $mysql = new MysqlDB(); $res = $mysql->connect($config); if ($res === false) { throw new RuntimeException("Failed to connect mysql server"); } else { $this->pool->push($mysql); } }); } } } public function get() { if ($this->pool->length() > 0) { $mysql = $this->pool->pop($this->config['master']['pool_get_timeout']); if (false === $mysql) { throw new RuntimeException("Pop mysql timeout"); } defer(function () use ($mysql) { //釋放 $this->pool->push($mysql); }); return $mysql; } else { throw new RuntimeException("Pool length <= 0"); } } }
MysqlDB.php
<?php if (!defined('SERVER_PATH')) exit("No Access"); class MysqlDB { private $master; private $slave; private $config; public function __call($name, $arguments) { if ($name != 'query') { throw new RuntimeException($name.":This command is not supported"); } else { return $this->_execute($arguments[0]); } } public function connect($config) { //主庫 $master = new Swoole\Coroutine\MySQL(); $res = $master->connect($config['master']); if ($res === false) { throw new RuntimeException($master->connect_error, $master->errno); } else { $this->master = $master; } //從庫 $slave = new Swoole\Coroutine\MySQL(); $res = $slave->connect($config['slave']); if ($res === false) { throw new RuntimeException($slave->connect_error, $slave->errno); } else { $this->slave = $slave; } $this->config = $config; return $res; } public function insert($table = '', $data = []) { $fields = ''; $values = ''; $keys = array_keys($data); foreach ($keys as $k) { $fields .= "`".addslashes($k)."`, "; $values .= "'".addslashes($data[$k])."', "; } $fields = substr($fields, 0, -2); $values = substr($values, 0, -2); $sql = "INSERT INTO `{$table}` ({$fields}) VALUES ({$values})"; return $this->_execute($sql); } public function update($table = '', $set = [], $where = []) { $arr_set = []; foreach ($set as $k => $v) { $arr_set[] = '`'.$k . '` = ' . $this->_escape($v); } $set = implode(', ', $arr_set); $where = $this->_where($where); $sql = "UPDATE `{$table}` SET {$set} {$where}"; return $this->_execute($sql); } public function delete($table = '', $where = []) { $where = $this->_where($where); $sql = "DELETE FROM `{$table}` {$where}"; return $this->_execute($sql); } public function select($table = '',$where = []) { $where = $this->_where($where); $sql = "SELECT * FROM `{$table}` {$where}"; return $this->_execute($sql); } private function _where($where = []) { $str_where = ''; foreach ($where as $k => $v) { $str_where .= " AND `{$k}` = ".$this->_escape($v); } return "WHERE 1 ".$str_where; } private function _escape($str) { if (is_string($str)) { $str = "'".$str."'"; } elseif (is_bool($str)) { $str = ($str === FALSE) ? 0 : 1; } elseif (is_null($str)) { $str = 'NULL'; } return $str; } private function _execute($sql) { if (strtolower(substr($sql, 0, 6)) == 'select') { $db = $this->_get_usable_db('slave'); } else { $db = $this->_get_usable_db('master'); } $result = $db->query($sql); if ($result === true) { return [ 'affected_rows' => $db->affected_rows, 'insert_id' => $db->insert_id, ]; } return $result; } private function _get_usable_db($type) { if ($type == 'master') { if (!$this->master->connected) { $master = new Swoole\Coroutine\MySQL(); $res = $master->connect($this->config['master']); if ($res === false) { throw new RuntimeException($master->connect_error, $master->errno); } else { $this->master = $master; } } return $this->master; } elseif ($type == 'slave') { if (!$this->slave->connected) { $slave = new Swoole\Coroutine\MySQL(); $res = $slave->connect($this->config['slave']); if ($res === false) { throw new RuntimeException($slave->connect_error, $slave->errno); } else { $this->slave = $slave; } } return $this->slave; } } }
try { MysqlPool::getInstance(get_config('mysql')); } catch (\Exception $e) { $serv->shutdown(); } catch (\Throwable $throwable) { $serv->shutdown(); }
<?php //新增 $demo = [ 'type' => 'SW', 'token' => 'Bb1R3YLipbkTp5p0', 'param' => [ 'class' => 'Order', 'method' => 'add', 'param' => [ 'code' => 'C'.mt_rand(1000,9999), 'name' => '訂單-'.mt_rand(1000,9999), ], ], ]; //編輯 $demo = [ 'type' => 'SW', 'token' => 'Bb1R3YLipbkTp5p0', 'param' => [ 'class' => 'Order', 'method' => 'edit', 'param' => [ 'id' => '4', 'name' => '訂單-'.mt_rand(1000,9999), ], ], ]; //刪除 $demo = [ 'type' => 'SW', 'token' => 'Bb1R3YLipbkTp5p0', 'param' => [ 'class' => 'Order', 'method' => 'del', 'param' => [ 'id' => '1', ], ], ]; //查詢 $demo = [ 'type' => 'SW', 'token' => 'Bb1R3YLipbkTp5p0', 'param' => [ 'class' => 'Order', 'method' => 'info', 'param' => [ 'code' => 'C4649' ], ], ]; $ch = curl_init(); $options = [ CURLOPT_URL => 'http://10.211.55.4:9509/', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => json_encode($demo), ]; curl_setopt_array($ch, $options); curl_exec($ch); curl_close($ch);
官方協程 MySQL 客戶端手冊:
https://wiki.swoole.com/wiki/...
你們能夠嘗試使用官方提供的其餘方法。
Demo 代碼僅供參考,裏面有不少不嚴謹的地方。
根據本身的須要進行修改,好比業務代碼相關驗證,CURD 方法封裝 ...
推薦一個完善的產品,Swoole 開發的 MySQL 數據庫鏈接池(SMProxy):
https://github.com/louislivi/...
上面的 Demo 須要源碼的,加我微信。(菜單-> 加我微信-> 掃我)
本文歡迎轉發,轉發請註明做者和出處,謝謝!