Node中MySQL连接池的更换以及MySQL连接池集群的使用

Node中MySQL连接池的更换以及MySQL连接池集群的使用

做业务逻辑,无论你在用户前面摆多少层花哨的东西,说到底是用户在跟数据库交流。

好像每做一个项目,数据库连接池都不可能不用,而不同的每种语言和不同的每种数据库连接池的调研与选择又不得不花去几天时间,真正写出来,测试是不是真正符合你的需求又是几天时间。

在Node中,我最初选择的是generic pool,原因是上次假期调用到,有看了下主页,感觉更新及时,还挺不错,所以就用了,使用的代码如下:

 /**
 * 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();
});
*/

无奈事实证明,这个连接池会在MySQL服务端主动关闭连接后,不仅不自动重连,还会把Node进程弄挂,不知是我设置有问题还是别的,正好有个契机调研到MySQL模块自带连接池也不错,完全逆反常理,真乃良心模块。

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有个缺点是没有常用连接池的一些配置,比如最小连接数,网上有人总结出数据库连接池常用配置:

{
  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.
}

不过问题不大,后来根据需求,又为MySQL Pool 加了集群,这是在看Node MySQL时无意发现的,这可是个好东西,加上加上:

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"
}

集群节点配置文件:

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
    }
};

主要参考:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容