weekeight.github.io icon indicating copy to clipboard operation
weekeight.github.io copied to clipboard

node mysql 一点事

Open weekeight opened this issue 9 years ago • 0 comments

安装

npm install mysql

简单使用

// 参照官网的simple example
var mysql = require('mysql');

var dbConnection = mysql.createConnection({
    host: '127.0.0.1',
    user: 'root',
    password: 'test',
    database: 'ua-collector'
});

  dbConnection.connect();
  dbConnection.query('select * from `records`', function(err, rows, fields){
    if(!err){
      console.log('Results: ', rows);
      res.render('ua-collector', {
       title: 'useragent收集器'
      });
    }else{
      console.log('Query error occurs: ' + err.stack);
    }
    dbConnection.end();
  });

查询数据库渲染页面

如果仅是按着官网的理解来,很容易走进误区,如下:

var express = require('express');
var mysql = require('mysql');

var app = express();
app.listen(3000);
var dbConnection = mysql.createConnection({
    host: '127.0.0.1',
    user: 'root',
    password: 'test',
    database: 'ua-collector'
});

app.get('/', function(req, res, next){
   dbConnection.connect();
    dbConnection.query('select * from `records`', function(err, rows, fields){
    if(!err){
      // console.log('Results: ', rows);
      res.json(rows);
    }else{
      console.log('Query error occurs: ' + err.stack);
    }
    dbConnection.end();
  });
});

第一次访问首页时一切正常,但是刷新页面第二次进入就会得到如下错误提示:

events.js:85
      throw er; // Unhandled 'error' event
            ^
Error: Cannot enqueue Handshake after invoking quit.
    at Protocol._validateEnqueue (/Users/benfchen/shinemo/ua-collector/node_modules/mysql/lib/protocol/Protocol.js:196:16)
    at Protocol._enqueue (/Users/benfchen/shinemo/ua-collector/node_modules/mysql/lib/protocol/Protocol.js:129:13)

其实错误原因是在只通过createConnection创立了一次连接,在第一次首页访问中可以正常查询数据库,但是马上就通过end关闭了连接,导致第二次想要再次连接时就报错了。第二次想要再查询数据库必须再次通过createConnection创立连接才行,也即是如下代码则可以正常运行:

var express = require('express');
var mysql = require('mysql');

var app = express();
app.listen(3000);


app.get('/', function(req, res, next){
    var dbConnection = mysql.createConnection({
        host: '127.0.0.1',
        user: 'root',
        password: 'test',
        database: 'ua-collector'
    });
   dbConnection.connect();
    dbConnection.query('select * from `records`', function(err, rows, fields){
    if(!err){
      // console.log('Results: ', rows);
      res.json(rows);
    }else{
      console.log('Query error occurs: ' + err.stack);
    }
    dbConnection.end();
  });
});

并发问题

理论上来说上面的代码可以正常运行,但是这里面存在一个巨大的隐患,每次请求都建立一次数据库连接,如果多个用户同时访问那么建立的连接数必定很多,服务器性能如果撑不住就直接挂了。这个取决于服务器性能、数据库皮配置以及并发请求数量是否能够平衡,但是在生产环境中采用这样的代码总不太可靠。

我在我的电脑macbook pro 2015机子上通过siege来做压力测试,并发连接3000没什么问题,但是更多就不清楚了,因为机子分不出更大的内存来模拟并发请求了。

如要通过siege做压力测试,可通过homebrew安装

brew install siege

// 模拟并发请求3000个
siege -c3000 http://localhost:3000

连接池

在生产环境,考虑多用户并发连接问题比较靠谱的是使用连接池来控制数据库的连接访问。

可通过createPool创建一个连接池,并配置好最大的连接数,这样多个连接请求就可以共用一个连接,并有mysql来自动处理请求排队和连接池的管理。

var express = require('express');
var mysql = require('mysql');

var app = express();
app.listen(3000);
var dbPool = mysql. createPool({ // 创建连接池
    connectionLimit : 10,
    host: '127.0.0.1',
    user: 'root',
    password: 'test',
    database: 'ua-collector'
});

app.get('/', function(req, res, next){
  dbPool.getConnection(function(err, connection){ // 从连接池中获取连接使用
    if(!err){
      connection.query('select * from `records`', function(err, rows, fields){
        if(!err){
          console.log('Results: ' + rows);
        }

        connection.release(); // 释放连接
      });
    }
  }); 

});

weekeight avatar Nov 04 '15 10:11 weekeight