Node中MySQL連接池的更換以及MySQL連接池集群的使用

Node中MySQL連接池的更換以及MySQL連接池集群的使用

做業(yè)務(wù)邏輯筐赔,無(wú)論你在用戶前面擺多少層花哨的東西捌锭,說(shuō)到底是用戶在跟數(shù)據(jù)庫(kù)交流昼汗。

好像每做一個(gè)項(xiàng)目朗涩,數(shù)據(jù)庫(kù)連接池都不可能不用尸诽,而不同的每種語(yǔ)言和不同的每種數(shù)據(jù)庫(kù)連接池的調(diào)研與選擇又不得不花去幾天時(shí)間圾笨,真正寫出來(lái),測(cè)試是不是真正符合你的需求又是幾天時(shí)間逊谋。

在Node中擂达,我最初選擇的是generic pool,原因是上次假期調(diào)用到胶滋,有看了下主頁(yè)板鬓,感覺(jué)更新及時(shí),還挺不錯(cuò)究恤,所以就用了俭令,使用的代碼如下:

 /**
 * Created by randy on 2017/6/29.
 */
var genericPool = require('generic-pool');
var DbDriver = require('mysql');
var settings = require('./settings');
/**
 * Step 1 - Create pool using a factory object
 */
const factory = {
    create: function () {
        return new Promise(function (resolve, reject) {
            var client = DbDriver.createConnection({
                host: settings.mysql.host,
                port: settings.mysql.port,
                database: settings.mysql.database,
                user: settings.mysql.user,
                password: settings.mysql.password,
                charset: settings.mysql.charset
            });
            client.connect(function (err) {
                if (err) {
                    console.log("SQL CONNECT ERROR: ", err);
                } else {
                    console.log("SQL CONNECT SUCCESSFUL.");
                    resolve(client)
                }
            });
        })
    },
    destroy: function (client) {
        return new Promise(function (resolve) {
            client.on('end', function () {
                resolve()
            });
            client.disconnect()
        })
    },
    error: function () {
        console.info('AAAAAAAA');
        this.create();
    }
};
var opts = {
    max: 10, // maximum size of the pool
    min: 5, // minimum size of the pool
   // acquireTimeoutMillis: 2,
   idleTimeoutMillis: 1000,
    log: true
};
var myPool = genericPool.createPool(factory, opts);
/**
 * Step 2 - Use pool in your code to acquire/release resources
 */
// acquire connection - Promise is resolved
// once a resource becomes available
const resourcePromise = myPool.acquire()
    .then(function (resource) {
        console.log('resource');
    })
    .catch(function (err) {
        console.log(err);
        return myPool.drain()
    });
module.exports = {
    doGetQuery: function (res, procName, handler) {
        var paraArray = [];
        var stmt = "CALL " + procName + "()";
        resourcePromise.then(function (client) {
            client.query(stmt, paraArray, function (err, rows, fields) {
                if (err) {
                    throw err;
                }
                handler(res, rows);
                //myPool.release(client);
            });
        })
            .catch(function (err) {
                // handle error - this is generally a timeout or maxWaitingClients
                // error
            });
    },
    doPostQuery: function (req, res, procName, handler) {
        req.on("data", function (chunk) {
                var params = JSON.parse(chunk.toString());
                var paraArray = [];
                var stmt = "CALL " + procName + "(";
                for (var param in params) {
                    stmt = stmt + "?, ";
                    paraArray.push(params[param]);
                }
                stmt = stmt.substring(0, stmt.length - 2) + ")";
                resourcePromise.then(function (client) {
                    client.query(stmt, paraArray, function (err, rows, fields) {
                        if (err) {
                            throw err;
                        }
                        handler(res, rows);
                        //myPool.release(client);
                    });
                })
                    .catch(function (err) {
                        // handle error - this is generally a timeout or maxWaitingClients
                        // error
                    });
            }
        )
    }
};
/**
 * Step 3 - Drain pool during shutdown (optional)
 */
// Only call this once in your application -- at the point you want
// to shutdown and stop using this pool.
/*
myPool.drain().then(function() {
    myPool.clear();
});
*/

無(wú)奈事實(shí)證明,這個(gè)連接池會(huì)在MySQL服務(wù)端主動(dòng)關(guān)閉連接后部宿,不僅不自動(dòng)重連抄腔,還會(huì)把Node進(jìn)程弄掛瓢湃,不知是我設(shè)置有問(wèn)題還是別的,正好有個(gè)契機(jī)調(diào)研到MySQL模塊自帶連接池也不錯(cuò)赫蛇,完全逆反常理绵患,真乃良心模塊。

var mysql = require('mysql');
var settings = require("./settings");
var config = {
    host: settings.mysql.host,
    port: settings.mysql.port,
    database: settings.mysql.database,
    user: settings.mysql.user,
    password: settings.mysql.password,
    charset: settings.mysql.charset,
    acquireTimeout: settings.mysql.acquireTimeout,
    waitForConnections: settings.mysql.waitForConnections,
    connectionLimit: settings.mysql.connectionLimit,
    queueLimit: settings.mysql.queueLimit
};
var pool = mysql.createPool(config);
pool.getConnection(function (err, connection) {
    console.log(err);
});
module.exports = {
    doGetQuery: (res, procName, handler) => {
        let paraArray = [];
        let stmt = "CALL " + procName + "()";
        pool.getConnection(function (err, connection) {
            connection.query(stmt, paraArray, function (err, rows, fields) {
                if (err) {
                    throw err;
                }
                handler(res, rows);
            });
            connection.release();
        });
    },
    doPostQuery: function (req, res, procName, handler) {
        req.on("data", function (chunk) {
                let params = JSON.parse(chunk.toString());
                let paraArray = [];
                let stmt = "CALL " + procName + "(";
                for (let param in params) {
                    stmt = stmt + "?, ";
                    paraArray.push(params[param]);
                }
                stmt = stmt.substring(0, stmt.length - 2) + ")";
                pool.getConnection((err, connection) => {
                    connection.query(stmt, paraArray, function (err, rows, fields) {
                        if (err) {
                            throw err;
                        }
                        handler(res, rows);
                    });
                    connection.release();
                });
            }
        )
    }
};

至此悟耘,連接池完畢落蝙,相比Generic poolMySQL Pool有個(gè)缺點(diǎn)是沒(méi)有常用連接池的一些配置暂幼,比如最小連接數(shù)筏勒,網(wǎng)上有人總結(jié)出數(shù)據(jù)庫(kù)連接池常用配置:

{
  connectionLimit : 50,
  queueWaitTimeout : 10000, // Same as acquireTimeout.
  pingCheckInterval : 10000, // The connection used in 10 seconds is reused without ping check.
  startConnections : 10, // 10 connections are created when the pool is started.
  minSpareConnections : 10, // 10 spare connections should be kept in the pool at all times.
  maxSpareConnections : 20, // No more than 20 spare connections.
  spareCheckInterval : 300000 // Check the spare connections every 5 minutes.
}

不過(guò)問(wèn)題不大,后來(lái)根據(jù)需求旺嬉,又為MySQL Pool 加了集群管行,這是在看Node MySQL時(shí)無(wú)意發(fā)現(xiàn)的,這可是個(gè)好東西邪媳,加上加上:

var mysql = require('mysql');
var settings = require("./settings");
var poolcfg = require("./msqNodeCfg");

var poolCluster = mysql.createPoolCluster();
poolCluster.add(settings.mysqlPoolCluster);
poolCluster.add('X', poolcfg.node01);
poolCluster.add('Y', poolcfg.node02);
poolCluster.add('Z', poolcfg.node03);


module.exports = {
    doGetQuery: (res, procName, handler) => {
        let paraArray = [];
        let stmt = "CALL " + procName + "()";
        poolCluster.getConnection(function (err, connection) {
            connection.query(stmt, paraArray, function (err, rows, fields) {
                if (err) {
                    throw err;
                }
                handler(res, rows);
            });
            connection.release();
        });
    },
    doPostQuery: function (req, res, procName, handler) {
        req.on("data", function (chunk) {
                let params = JSON.parse(chunk.toString());
                let paraArray = [];
                let stmt = "CALL " + procName + "(";
                for (let param in params) {
                    stmt = stmt + "?, ";
                    paraArray.push(params[param]);
                }
                stmt = stmt.substring(0, stmt.length - 2) + ")";
                poolCluster.getConnection((err, connection) => {
                    connection.query(stmt, paraArray, function (err, rows, fields) {
                        if (err) {
                            throw err;
                        }
                        handler(res, rows);
                    });
                    connection.release();
                });
            }
        )
    }
};

配置文件如下:
主配置文件:

mysql: {
    host: "127.0.0.1",
    port: 3306,
    user: "root",
    password: "root",
    database: "db_test",
    charset: "utf8"
},
mysqlPool: {
    acquireTimeout: 10000,
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0
},
mysqlPoolCluster: {
    canRetry: true,
    removeNodeErrorCount: 5,
    restoreNodeTimeout: 0,
    defaultSelector: "RR"
}

集群節(jié)點(diǎn)配置文件:

var settings = require("./settings");
module.exports = {
    node01: {
        host: '192.168.1.240',
        port: settings.mysql.port,
        database: settings.mysql.database,
        user: settings.mysql.user,
        password: "root",
        charset: settings.mysql.charset,
        acquireTimeout: settings.mysqlPool.acquireTimeout,
        waitForConnections: settings.mysqlPool.waitForConnections,
        connectionLimit: settings.mysqlPool.connectionLimit,
        queueLimit: settings.mysqlPool.queueLimit
    },
    node02: {
        host: "192.168.1.122",
        port: settings.mysql.port,
        database: settings.mysql.database,
        user: settings.mysql.user,
        password: "root",
        charset: settings.mysql.charset,
        acquireTimeout: settings.mysqlPool.acquireTimeout,
        waitForConnections: settings.mysqlPool.waitForConnections,
        connectionLimit: settings.mysqlPool.connectionLimit,
        queueLimit: settings.mysqlPool.queueLimit
    },
    node03: {
        host: '192.168.1.105',
        port: settings.mysql.port,
        database: settings.mysql.database,
        user: settings.mysql.user,
        password: "root",
        charset: settings.mysql.charset,
        acquireTimeout: settings.mysqlPool.acquireTimeout,
        waitForConnections: settings.mysqlPool.waitForConnections,
        connectionLimit: settings.mysqlPool.connectionLimit,
        queueLimit: settings.mysqlPool.queueLimit
    }
};

主要參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末病瞳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子悲酷,更是在濱河造成了極大的恐慌套菜,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件设易,死亡現(xiàn)場(chǎng)離奇詭異逗柴,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)顿肺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門戏溺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人屠尊,你說(shuō)我怎么就攤上這事旷祸。” “怎么了讼昆?”我有些...
    開(kāi)封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵托享,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我浸赫,道長(zhǎng)闰围,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任既峡,我火速辦了婚禮羡榴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘运敢。我一直安慰自己校仑,他們只是感情好忠售,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著迄沫,像睡著了一般稻扬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邢滑,一...
    開(kāi)封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音愿汰,去河邊找鬼困后。 笑死,一個(gè)胖子當(dāng)著我的面吹牛衬廷,可吹牛的內(nèi)容都是我干的摇予。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吗跋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼侧戴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起跌宛,我...
    開(kāi)封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤酗宋,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后疆拘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕猫,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年哎迄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了回右。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漱挚,死狀恐怖翔烁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旨涝,我是刑警寧澤蹬屹,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站白华,受9級(jí)特大地震影響哩治,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衬鱼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一业筏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸟赫,春花似錦蒜胖、人聲如沸消别。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寻狂。三九已至,卻和暖如春朋沮,著一層夾襖步出監(jiān)牢的瞬間蛇券,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工樊拓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纠亚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓筋夏,卻偏偏與公主長(zhǎng)得像蒂胞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子条篷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容