Swoole WebSocket 實現(xiàn)mysql實時數(shù)據(jù)展示

最近在學習swoole悴势,自己完成下論壇里留下的作業(yè)胸私,通過swoole_websocket實時展示mysql數(shù)據(jù)吹截,有個遺留問題瘦陈,如何判斷mysql是否有增刪改,我想到的方法有:
1波俄、在應用層中有增刪改時晨逝,發(fā)一個消息到消息隊列來監(jiān)聽。
2懦铺、解析mysql bin-log日志捉貌。
3、觸發(fā)器冬念。
現(xiàn)在的解決辦法是利用觸發(fā)器趁窃,例子中我只監(jiān)聽了一個表,當有多個表時急前,需要添加大量觸發(fā)器醒陆,觸發(fā)器本身占用很多資源,太多觸發(fā)器也不好管理裆针,之后會再想辦法解析下bin-log日志來監(jiān)聽Mysql數(shù)據(jù)變化刨摩。

服務端代碼

<?php
/**
 * Created by PhpStorm.
 * User: qyc
 * Date: 2017/10/22
 * Time: 下午4:40
 */

define('HOST', '0.0.0.0');
define('PORT', '9502');
define('WORKER_NUM', 8);
define('DISPATCH_MODE', 2);
define('DAEMONIZE', 0);

class swoole_ws
{
    private $pdo;

    private $server;

    //這里寫死了數(shù)據(jù)表,之后完成數(shù)據(jù)庫監(jiān)聽后改寫這里邏輯
    private $table
        = [
            'swoole_test',
        ];

    public function __construct()
    {
        $this->server = new swoole_websocket_server(HOST, PORT);
        $this->server->set(
            [
                //開啟woker進程數(shù)
                'worker_num'    => WORKER_NUM,
                //請求分發(fā)策略世吨,
                'dispatch_mode' => DISPATCH_MODE,
                //是否守護進程
                'daemonize'     => DAEMONIZE,
            ]
        );
        $this->server->on('message', [$this, 'onMessage']);
        $this->server->on('open', [$this, 'onOpen']);
        $this->server->on('workerStart', [$this, 'onWorkerStart']);
        $this->server->start();
    }

    //woker進程
    public function onWorkerStart(swoole_websocket_server $server, $worker_id)
    {
        if ($worker_id == 0) {
            // 0 worker進程開啟一個定時器去監(jiān)聽mysql數(shù)據(jù)變化
            $this->server->tick(500, [$this, 'onTick']);
        }
        //每個worker進程維持一個pdo連接
        $this->pdo = new PDO("mysql:host=localhost;dbname=swoole_ws", "root", "root");
    }

    //接受客戶端數(shù)據(jù)
    public function onMessage(swoole_websocket_server $server, swoole_websocket_frame $frame)
    {
//        echo $frame->data;   //客戶端發(fā)送的數(shù)據(jù)
//        echo $server->worker_id;
    }

    //客戶端 服務端建立連接并完成握手后的回調
    public function onOpen(swoole_websocket_server $server, swoole_http_request $request)
    {
        //第一次連接去獲取一下Mysql數(shù)據(jù)
        $this->update();
    }

    private function update()
    {
        $res = [];
        foreach ($this->table as $table) {
            $res[$table] = $this->getTableData($table);
        }
        foreach ($this->server->connections as $connection) {
            //向所有客戶端發(fā)送數(shù)據(jù)
            $this->server->push($connection, json_encode($res));
        }
    }

    //獲取表數(shù)據(jù)
    private function getTableData($table)
    {
        $sql = 'select * from ' . $table;
        try {
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute();
            $res = $stmt->fetchAll(PDO::FETCH_ASSOC);

            return $res ?: [];
        } catch (Exception $e) {
            return [];
        }
    }

    //定時器回調
    public function onTick()
    {
        /*
         * is_update表記錄表是否更新過
         * swoole_test表添加了3個觸發(fā)器澡刹, after insert、update耘婚、delete罢浇,
         * 會向is_update表更新swoole_test是否有更新操作
         */
        try {
            $sql = 'select is_update from is_update where table_name = "swoole_test"';
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute();
            $res = $stmt->fetchAll(PDO::FETCH_ASSOC);
            if ( ! $res) {
                return [];
            }
            if ($res[0]['is_update'] == 1) {
                //當is_update字段為1時表明數(shù)據(jù)有更新,向客戶端推送消息
                $this->update();
                //更新下表更新字段
                $update = 'update is_update set is_update=0 where table_name = "swoole_test"';
                $stmt = $this->pdo->prepare($update);
                $stmt->execute();
            }
        } catch (Exception $e) {
            $this->pdo = new PDO("mysql:host=localhost;dbname=swoole_ws", "root", "root");
        }
    }
}

new swoole_ws();

客戶端代碼

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Mysql實時數(shù)據(jù)</title>
    <link rel="stylesheet" 
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <!--[if lt IE 9]>
    <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
    <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"
            integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
            crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">swoole_test</h3>
        </div>
        <div class="panel-body">
            <table class="table table-bordered  table-hover">
                <thead id="thead">
                </thead>
                <tbody id="tbody">
                </tbody>
            </table>
        </div>
    </div>
</div>
<script>
    var websocket = new WebSocket('ws://127.0.0.1:9502');

    websocket.onopen = function (event) {
        console.log('websocket connect');
        websocket.send('hello swoole');
    };

    websocket.onclose = function (event) {
        console.log('websocket close');
    };

    websocket.onerror = function (event, e) {
        console.log('error occured:' + event.data);
    };

    websocket.onmessage = function (event) {

        data = JSON.parse(event.data)['swoole_test'];
        var th = '<tr>';
        var width = 1 / json_length(data[0]) * 100;
        for (var key in data[0]) {
            th += "<th style='width:" + width + "%'>" + key + "</th>";
        }
        th += '</tr>';
        $("#thead").html(th);

        var tbody = '';
        for (var line in data) {
            tbody += '<tr>';
            var td = '';
            for (var column in data[line]) {
                td += "<td>" + data[line][column] + "</td>";
            }
            tbody += td + '</tr>';
        }
        $("#tbody").html(tbody);
    };

    function json_length(json) {
        var length = 0;
        for (var item in json) {
            length++;
        }
        return length;
    }
</script>
</body>
</html>

觸發(fā)器

DELIMITER $$
/*更新觸發(fā)器*/
DROP TRIGGER IF EXISTS swoole_test_is_update;
$$
CREATE TRIGGER swoole_test_is_update AFTER UPDATE ON swoole_test FOR EACH ROW
BEGIN
  UPDATE `is_update`
  SET    is_update = 1
  WHERE  TABLE_NAME = 'swoole_test';
END;
$$
/*添加觸發(fā)器*/
DROP TRIGGER IF EXISTS swoole_test_is_insert;
$$
CREATE TRIGGER swoole_test_is_insert AFTER UPDATE ON swoole_test FOR EACH ROW
BEGIN
  UPDATE `is_update`
  SET    is_update = 1
  WHERE  TABLE_NAME = 'swoole_test';
END;
$$
/*刪除觸發(fā)器*/
DROP TRIGGER IF EXISTS swoole_test_is_delete;
$$
CREATE TRIGGER swoole_test_is_delete AFTER UPDATE ON swoole_test FOR EACH ROW
BEGIN
  UPDATE `is_update`
  SET    is_update = 1
  WHERE  TABLE_NAME = 'swoole_test';
END;
$$
DELIMITER ;

開啟websocker服務端

php swoole_ws;

運行效果

現(xiàn)在訪問前端頁面沐祷,對數(shù)據(jù)庫進行增刪改操作測試效果嚷闭。

1.png

結語

這只是個swoole_websocket練習,熟悉一下戈轿,大家可以看看Swoole官方文檔進行學習凌受,會有不錯的提升,之后會做個即時聊天工具玩玩思杯,Just code for fun ~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末胜蛉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子色乾,更是在濱河造成了極大的恐慌誊册,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暖璧,死亡現(xiàn)場離奇詭異案怯,居然都是意外死亡,警方通過查閱死者的電腦和手機澎办,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門嘲碱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來金砍,“玉大人,你說我怎么就攤上這事麦锯∷〕恚” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵扶欣,是天一觀的道長鹅巍。 經(jīng)常有香客問我,道長料祠,這世上最難降的妖魔是什么骆捧? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮髓绽,結果婚禮上敛苇,老公的妹妹穿的比我還像新娘。我一直安慰自己梧宫,他們只是感情好接谨,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著塘匣,像睡著了一般脓豪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忌卤,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天扫夜,我揣著相機與錄音,去河邊找鬼驰徊。 笑死笤闯,一個胖子當著我的面吹牛,可吹牛的內容都是我干的棍厂。 我是一名探鬼主播颗味,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼牺弹!你這毒婦竟也來了浦马?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤张漂,失蹤者是張志新(化名)和其女友劉穎晶默,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體航攒,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡磺陡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片币他。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡坞靶,死狀恐怖,靈堂內的尸體忽然破棺而出圆丹,到底是詐尸還是另有隱情滩愁,我是刑警寧澤躯喇,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布辫封,位于F島的核電站,受9級特大地震影響廉丽,放射性物質發(fā)生泄漏倦微。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一正压、第九天 我趴在偏房一處隱蔽的房頂上張望欣福。 院中可真熱鬧,春花似錦焦履、人聲如沸拓劝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郑临。三九已至,卻和暖如春屑宠,著一層夾襖步出監(jiān)牢的瞬間厢洞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工典奉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留躺翻,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓卫玖,卻偏偏與公主長得像公你,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子假瞬,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容