如何解决nodejs uncaughtException:连接已释放错误和MaxListenersExceededWarning?

问题描述 投票:2回答:1

我正在构建一个快递服务器,以从我的前端接收请求(一个包含10个项目的字典),然后将数据保存到数据库中。下面是我的代码。我发现我的代码可以正常工作,查询确实将记录保存回Db。但是在每个for循环中,此错误都会在服务器中返回。是什么导致此错误和MaxListenersExceededWarning?

The request data: 
{{.....}, {.....}, {.....}, {.....}, {.....}} #10 item

Code:
connection.js:
const p = mysql.createPool({
  "connectionLimit" : 100,
  "host": "example.org",
  "user": "test",
  "password": "test",
  "database": "test",
  "multipleStatements": true
});

const getConnection = function(callback) {
    p.getConnection(function(err, connection) {
        callback(err, connection)
    })
};

module.exports = getConnection

routers.js
router.post('/test', (req, res) => {
    getConnection(function(err, conn){
        if (err) {
            return res.json({ success: false, error: err })
        } else {
          const dict = req.body;
          Object.keys(dict).forEach(function(r){
              #putting dict's value to query 
              query = "UPDATE ......;"
              conn.query(query, function (err, result, fields) {
                conn.release()
                console.log(query)
                  if (err) {
                      console.log("err")
                      return res.json({ success: false, error: err });
                  }
              });
            });
          }
        });
        return res.json({ success: true });
    });

Error:
error: uncaughtException: Connection already released
Error: Connection already released
    at Pool.releaseConnection (/home/node_modules/mysql/lib/Pool.js:138:13)
    at PoolConnection.release (/home/node_modules/mysql/lib/PoolConnection.js:35:15)
    at Query.<anonymous> (/home/routes/test.js:276:22)
    at Query.<anonymous> (/home/node_modules/mysql/lib/Connection.js:526:10)
    at Query._callback (/home/node_modules/mysql/lib/Connection.js:488:16)
    at Query.Sequence.end (/home/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
    at Query._handleFinalResultPacket (/home//node_modules/mysql/lib/protocol/sequences/Query.js:149:8)
    at Query.OkPacket (/home//node_modules/mysql/lib/protocol/sequences/Query.js:74:10)
    at Protocol._parsePacket (/home//node_modules/mysql/lib/protocol/Protocol.js:291:23)
    at Parser._parsePacket (/home//node_modules/mysql/lib/protocol/Parser.js:433:10)
(node:15881) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added. Use emitter.setMaxListeners() to increase limit
javascript mysql node.js express database-connection
1个回答
2
投票

正在从池中检索一个连接(conn),并用于在forEach循环中启动10个查询。

当第一个查询完成运行时,其回调的第一步是:conn.release()。连接已释放。

当第二个查询完成运行时,其回调也会尝试释放连接,从而导致错误。

此问题可以通过多种方式解决:

使用计数器解决

在数据库查询的回调中,在调用call.release之前,请检查已处理的查询数,并且仅在处理最后一个产品时关闭连接。

      const dict = req.body;

      // initialize counter
      let itemCount = 0
          , errors = []

      Object.keys(dict).forEach(function(r){
          #putting dict's value to query 
          query = "UPDATE ......;"
          conn.query(query, function (err, result, fields) {


            // check whether this is the last callback
            if (itemCount === dict.length-1) {
                conn.release()

                let result = errors.length ? { success: false, error: errors } : { success: true }

                res.json(result)

            }

            // increment counter
            itemCount++

            console.log(query)
              if (err) {
                  console.log("err")
                  errors.push(err)
              }
          });
        });

Editres.json调用也存在问题:在问题代码中,始终执行res.json({ success: true }),而无需等待查询的执行结果。上面修改的代码示例在执行所有查询后仅调用res.json一次,这是应调用res.json的唯一位置。这意味着修改客户端代码,使其可以处理一系列错误,而不是仅处理一个错误。

通过使用递归函数代替for循环来解决。

使用for循环执行异步代码不是一个好习惯。每当数据量太大时,您可能会遇到Maximum call stack size exceeded错误。

相反,创建一个递归函数(例如updateDictItem)来一次处理一个更新查询。在this article中阅读有关node.js中异步模式的更多信息。

其他可能的增强功能

而不是触发十个数据库查询,值得考虑将所有更新分组在一个MERGE update statement中,否则将所有更新分组在一个MERGE中。

© www.soinside.com 2019 - 2024. All rights reserved.