精华 在Node.js使用mysql模块时遇到的坑
发布于 3 年前 作者 leizongmin 35551 次浏览

之前写了个小程序Node News,用到了MySQL数据库,在本地测试均没神马问题。放上服务器运行一段时间后,偶然发现打开页面的时候页面一直处于等待状态,直到Nginx返回超时错误。于是上服务器检查了遍,发现程序仍然在运行,且能正确记录每次的请求,再修改代码跟踪调试,原来是在查询数据库的时候,回调一直没有被执行,程序就挂在那里了。

想了很久也想不明白为神马mysql模块没有执行回调,最后突然想起来去看了下错误日志,才发现有个“No reconnection after connection lost”错误没有被捕捉到,原来是连接丢失了,上github上看了下文档和issues,上面说到连接丢失后不会自动重新连接,会触发error事件。我赶紧给程序添加了断线后自动重连功能,现在已正常运行了10多天。

MySQL中有一个名叫wait_timeout的变量,表示操作超时时间,当连接超过一定时间没有活动后,会自动关闭该连接,这个值默认为28800(即8小时)。

自动重连数据库的代码:

function handleError (err) {
  if (err) {
    // 如果是连接断开,自动重新连接
    if (err.code === 'PROTOCOL_CONNECTION_LOST') {
      connect();
    } else {
      console.error(err.stack || err);
    }
  }
}

// 连接数据库
function connect () {
  db = mysql.createConnection(config);
  db.connect(handleError);
  db.on('error', handleError);
}

var db;
connect();

网上流传的大多数使用mysql模块的代码,往往忽略了这个问题,一不小心就让一拨又一拨的人往坑里踩了。

有童鞋回复问使用pool又会怎样,于是去看了下mysql模块的源码:目前可在npm中安装到的最新版本为2.0.0-alpha7,使用mysql.createPool()来创建的pool没办法自动处理连接被关闭的问题,但是在github上的版本已经修复了(应该还没发布到npm上),当触发了connection的error事件时,会把该connection对象从连接池中移除。(源码:https://github.com/felixge/node-mysql/blob/master/lib/Pool.js#L119

使用pool的代码:

var mysql = require('mysql');
var pool  = mysql.createPool(config);

pool.getConnection(function(err, connection) {
  // Use the connection
  connection.query( 'SELECT something FROM sometable', function(err, rows) {
    // And done with the connection.
    connection.end();

    // Don't use the connection here, it has been returned to the pool.
  });
});

参考: 《Nodejs使用mysql》 《No reconnection after connection lost》 《mysql自动断开连接的问题处理方案》 《MySQL数据库连接超时(wait_timeout)问题的处理

原文地址:http://writings.ucdok.com/articles/problems-on-nodejs-mysql 转载时请注明出处。

34 回复

不知道在

var mysql = require('mysql');

var pool = mysql.createPool({ host : ‘example.org’, user : ‘bob’, password : ‘secret’ });

pool.getConnection(function(err, connection) { // connected! (unless err is set) });

情况会表现得如何。。

老雷好贴,顶起~

同样不会自动重连

@leizongmin 最新版本的pool已经可以自动处理该问题了

果断遇到这个情况了, = 。= 天真以为这种事情,不会发生在自己身上,审核的时候发现网站 连接不了,要好好热修复了。。

请问要更新到最新版本,该怎么弄呢?

最新版本已经解决了连接池断开后不能自动连接问题:npm install mysql@2.0.0-alpha8

为什么node也有类似,之前知道python的一个sqlalchemy也有Mysql has gone away的问题。

这不是Node.js的问题,而是MySQL的一个机制,在客户端长时间不活动时,自动关闭其连接。而由于客户端程序不够完善,未能正确处理而已。

有这么坑吗。表示没有遇到 过。

要么是你不是用这个模块,要么是你刚好赶上了好时代人家把这个问题Fixed了你再用的,要么是你很厉害写代码很谨慎。

@leizongmin 好吧。 我生在新中国长在红旗下了。

https://github.com/sequelize/sequelize 对于这个支持多种方言的数据库怎么看?支持MySQL, SQLite and PostgreSQL

但我記得handleError 很久以前官方文件就有了 應該使用這個module的人都會會加

如果不想要被wait timeout踢掉 建議一段時間就作ping 這樣可以一直保持連接

pool的我是用generic-pool自己作掉了

不過曾經有遇到過一個問題是 跨internet連接mysql 有時會突然完全沒有回應 handleError也沒收到任何錯誤 不知道這bug改掉了沒…

但是当用到connect-mysql第三方包来存session信息时却解决不了

这个是模块不完善导致的问题,新的mysql模块,在使用pool的时候已经可以自动重连了,而connect-mysql模块应该使用mysql的pool来建立连接。 要么你等待connect-mysql模块的作者来完善,要么就干脆基于connect-mysql的代码,自己来改一下了。

应该第一时间想到查看日志 (☆_☆)

mysql模块里面的pool非常好用,可以设置自动重连,poolcluster还可以支持多个master和slave

这是一年前的帖子……

三年前就有Pool了么。。。

@Jiasm 可能不止三年前了……

好文章,避免了一个大坑

楼主好,如果pool 用end()释放资源的话,再次进行数据库操作时会提示错误:

Error: Connection already released 之后再重新连接,导致系统卡掉,请问有什么解决方法吗

@bykege 使用end()释放资源后,如果要再继续操作,使用getConnection()来获取资源

@leizongmin 是否可以给个demo

@bykege 本文那段代码就是demo了

@leizongmin

pool.getConnection(function(err, connection) {
  // Use the connection
  connection.query( 'SELECT something FROM sometable', function(err, rows) {
    // And done with the connection.
    connection.end();

    // Don't use the connection here, it has been returned to the pool.
  });
});

用这种方法,链接第一次时可行,再进行数据库链接会由于 connection.end()而在终端报错,停顿1秒后才再度链接

@bykege

function myQuery(sql, callback) {
  pool.getConnection(function (err, conn) {
    if (err) return callback(err);
    conn.query(sql, function (err, ret) {
      conn.end();
      callback(err, ret);
    }
  }
}

myQuery('ooxx', console.log)
myQuery('xxoo', console.log)

我从一开始就用的easymysql ,不用自己end ,带pool ,带心跳,稳定的一比,不过也很久没更新了,依然好用

回到顶部