92

我已经实现了以下代码:

module.exports = {
    getDataFromUserGps: function(callback)
    {
        connection.connect();
        connection.query("SELECT * FROM usergps", 
            function(err, results, fields) {
                if (err) return callback(err, null);
                return callback(null, results);
            }
        ); 
        connection.end();
    },
    loginUser: function(login, pass, callback)
    {
        connection.connect();
        connection.query(
            "SELECT id FROM users WHERE login = ? AND pass = ?",
            [login, pass],
            function(err, results, fields) 
            {
                if (err) return callback(err, null);
                return callback(null, results);
            }
        ); 
        connection.end();
    },
    getUserDetails: function(userid, callback)
    {
        connection.connect();
        connection.query(
            "SELECT * FROM userProfilDetails LEFT JOIN tags ON userProfilDetails.userId = tags.userId WHERE userProfilDetails.userid = ?",
            [userid],
            function(err, results, fields)
            {
                if (err) return callback(err, null);
                return callback(null, results);
            }
        );
        connection.end();
    },
    addTags: function(userId, tags)
    {
        connection.connect();
        connection.query(
            "INSERT INTO tag (userId, tag) VALUES (?, ?)",
            [userId, tags],
            function(err, results, fields)
            {
                if (err) throw err;
            }
        )
        connection.end();
    }
}

一切都只在第一次工作得很好。如果我想第二次“使用”查询,我会收到以下错误:

Cannot enqueue Handshake after invoking quit

我试过不.end()连接,但没有帮助。

我该如何解决这个问题?

4

10 回答 10

261

如果您使用 node-mysql 模块,只需删除 .connect 和 .end。刚刚自己解决了这个问题。显然,他们在最后一次迭代中加入了不必要的代码,这也是错误的。如果您已经运行了 createConnection 调用,则不需要连接

于 2013-01-09T21:47:40.750 回答
60

根据:

TL;DRcreateConnection您需要在每次断开连接后调用该方法来建立新连接。

注意:如果您正在处理 Web 请求,那么您不应该在每个请求上都结束连接。只需在服务器启动时创建一个连接,并始终使用连接/客户端对象进行查询。您可以侦听错误事件以处理服务器断开连接和重新连接。完整代码 在这里


从:

它说:

服务器断开连接

由于网络问题、服务器超时或服务器崩溃,您可能会失去与 MySQL 服务器的连接。所有这些事件都被认为是致命错误,并且将具有err.code = 'PROTOCOL_CONNECTION_LOST'. 有关详细信息,请参阅错误处理部分。

处理此类意外断开连接的最佳方法如下所示:

function handleDisconnect(connection) {
  connection.on('error', function(err) {
    if (!err.fatal) {
      return;
    }

    if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
      throw err;
    }

    console.log('Re-connecting lost connection: ' + err.stack);

    connection = mysql.createConnection(connection.config);
    handleDisconnect(connection);
    connection.connect();
  });
}

handleDisconnect(connection);

正如您在上面的示例中看到的,重新连接连接是通过建立新连接来完成的。一旦终止,现有的连接对象就不能按设计重新连接。

使用 Pool,断开连接的连接将从池中删除,从而为下一次 getConnection 调用创建新连接腾出空间。


我已经调整了函数,每次需要连接时,初始化函数都会自动添加处理程序:

function initializeConnection(config) {
    function addDisconnectHandler(connection) {
        connection.on("error", function (error) {
            if (error instanceof Error) {
                if (error.code === "PROTOCOL_CONNECTION_LOST") {
                    console.error(error.stack);
                    console.log("Lost connection. Reconnecting...");

                    initializeConnection(connection.config);
                } else if (error.fatal) {
                    throw error;
                }
            }
        });
    }

    var connection = mysql.createConnection(config);

    // Add handlers.
    addDisconnectHandler(connection);

    connection.connect();
    return connection;
}

初始化连接:

var connection = initializeConnection({
    host: "localhost",
    user: "user",
    password: "password"
});

小建议:这可能不适用于所有人,但我确实遇到了与范围有关的小问题。如果 OP 认为此编辑是不必要的,那么他/她可以选择将其删除。对我来说,我必须在 中更改一行initializeConnection,这var connection = mysql.createConnection(config);只是

connection = mysql.createConnection(config);

原因是如果connection是程序中的全局变量,那么之前的问题是您connection在处理错误信号时创建了一个新变量。但是在我的 nodejs 代码中,我一直使用相同的全局connection变量来运行查询,因此 newconnection将在initalizeConnection方法的本地范围内丢失。但是在修改中,它确保全局connection变量被重置如果您遇到称为的问题,这可能是相关的

致命错误后无法排队查询

在失去连接后尝试执行查询然后成功重新连接后。这可能是OP的错字,但我只是想澄清一下。

于 2013-05-03T18:58:58.447 回答
23

我遇到了同样的问题,谷歌把我带到了这里。我同意@Ata 的观点,即仅删除是不正确的end()。进一步谷歌搜索后,我认为使用pooling是一种更好的方法。

关于池的 node-mysql 文档

就像这样:

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

pool.getConnection(function(err, connection) {
    connection.query( 'bla bla', function(err, rows) {
        connection.release();
    });
});
于 2013-09-04T10:16:28.763 回答
7

不要在函数内部进行 connect() 和 end()。这将导致重复调用该函数时出现问题。仅建立连接

var connection = mysql.createConnection({
      host: 'localhost',
      user: 'node',
      password: 'node',
      database: 'node_project'
    })

connection.connect(function(err) {
    if (err) throw err

});

一次并重用该连接。

函数内部

function insertData(name,id) {

  connection.query('INSERT INTO members (name, id) VALUES (?, ?)', [name,id], function(err,result) {
      if(err) throw err
  });


}
于 2017-07-10T12:20:34.790 回答
7

AWS Lambda 函数

使用mysql.createPool()connection.destroy()

这样,新的调用使用已建立的池,但不保持函数运行。即使您没有获得池的全部好处(每个新连接都使用一个新连接而不是现有连接),但它使得第二次调用可以建立一个新连接,而不必先关闭前一个连接。

关于connection.end()

这可能会导致后续调用引发错误。调用仍将稍后重试并工作,但有延迟。

关于mysql.createPool()connection.release()

Lambda 函数将继续运行,直到计划的超时,因为仍然有一个打开的连接。

代码示例

const mysql = require('mysql');

const pool = mysql.createPool({
  connectionLimit: 100,
  host:     process.env.DATABASE_HOST,
  user:     process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
});

exports.handler = (event) => {
  pool.getConnection((error, connection) => {
    if (error) throw error;
    connection.query(`
      INSERT INTO table_name (event) VALUES ('${event}')
    `, function(error, results, fields) {
      if (error) throw error;
      connection.destroy();
    });
  });
};
于 2019-02-28T23:47:35.683 回答
2

代替connection.connect();使用 -

if(!connection._connectCalled ) 
{
connection.connect();
}

如果它已经被调用,则connection._connectCalled =true&
它不会执行connection.connect()

注意- 不要使用connection.end();

于 2018-08-17T09:48:41.960 回答
1

我认为这个问题与我的类似:

  1. 连接到 MySQL
  2. 结束 MySQL 服务(不应退出节点脚本)
  3. 启动 MySQL 服务,Node 重新连接 MySQL
  4. 查询 DB -> FAIL(致命错误后无法排队查询。)

我通过使用 Promise (q) 重新创建新连接解决了这个问题。

mysql-con.js

'use strict';
var config          = require('./../config.js');
var colors          = require('colors');
var mysql           = require('mysql');
var q               = require('q');
var MySQLConnection = {};

MySQLConnection.connect = function(){
    var d = q.defer();
    MySQLConnection.connection = mysql.createConnection({
        host                : 'localhost',
        user                : 'root',
        password            : 'password',
        database            : 'database'
    });

    MySQLConnection.connection.connect(function (err) {
        if(err) {
            console.log('Not connected '.red, err.toString().red, ' RETRYING...'.blue);
            d.reject();
        } else {
            console.log('Connected to Mysql. Exporting..'.blue);
            d.resolve(MySQLConnection.connection);
        }
    });
    return d.promise;
};

module.exports = MySQLConnection;

mysqlAPI.js

var colors          = require('colors');
var mysqlCon        = require('./mysql-con.js');
mysqlCon.connect().then(function(con){
   console.log('connected!');
    mysql = con;
    mysql.on('error', function (err, result) {
        console.log('error occurred. Reconneting...'.purple);
        mysqlAPI.reconnect();
    });
    mysql.query('SELECT 1 + 1 AS solution', function (err, results) {
            if(err) console.log('err',err);
            console.log('Works bro ',results);
    });
});

mysqlAPI.reconnect = function(){
    mysqlCon.connect().then(function(con){
      console.log("connected. getting new reference");
        mysql = con;
        mysql.on('error', function (err, result) {
            mysqlAPI.reconnect();
        });
    }, function (error) {
      console.log("try again");
        setTimeout(mysqlAPI.reconnect, 2000);
    });
};

我希望这有帮助。

于 2015-02-01T22:17:32.853 回答
0

您可以使用调试:假,

示例://mysql连接

var dbcon1 = mysql.createConnection({
      host: "localhost",
      user: "root",
      password: "",
      database: "node5",
      debug: false,
    });
于 2019-06-07T08:34:12.520 回答
0

解决方案:为防止此错误(对于 AWS LAMBDA):

为了退出“Nodejs事件循环”,您必须结束连接,然后重新连接。添加下一个代码以调用回调:

connection.end( function(err) {
        if (err) {console.log("Error ending the connection:",err);}

       //  reconnect in order to prevent the"Cannot enqueue Handshake after invoking quit"

         connection = mysql.createConnection({
                host     : 'rds.host',
                port     :  3306,
                user     : 'user',
               password : 'password',
               database : 'target database'

               });
        callback(null, {
            statusCode: 200,
            body: response,

        });
    });
于 2018-04-20T01:26:20.717 回答
0

如果你想得到一个 lambda,我发现结束处理程序context.done()让 lambda 完成。在添加那 1 行之前,它会一直运行直到超时。

于 2019-01-18T23:14:36.017 回答