简体   繁体   English

如何解决 nodejs uncaughtException: Connection already Release 错误和 MaxListenersExceededWarning?

[英]How to solve nodejs uncaughtException: Connection already released error and MaxListenersExceededWarning?

I am building an express server to receive request (a dict with 10 items) from my react front end and then save the data to database.我正在构建一个快速服务器以从我的 React 前端接收请求(一个包含 10 个项目的字典),然后将数据保存到数据库中。 Below is my code.下面是我的代码。 I found that my code is work and the query does save the record back to Db.我发现我的代码可以正常工作,并且查询确实将记录保存回 Db。 But in each for loop, this error is returned in server.但是在每个 for 循环中,这个错误都会在 server.js 中返回。 What cause this error and the MaxListenersExceededWarning?是什么导致此错误和 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

One connection ( conn ) is being retrieved from the pool, and is used to launch 10 queries in the forEach loop.正在从池中检索一个连接 ( conn ),并用于在forEach循环中启动 10 个查询。

When the first query finishes to run, the first step of its callback is: conn.release() .当第一个查询完成运行时,其回调的第一步是: conn.release() The connection is released.连接被释放。

When the second query finishes to run, its callback also tries to release the connection,causing the error.当第二个查询完成运行时,其回调也尝试释放连接,从而导致错误。

This problem might be solved in multiple ways:这个问题可以通过多种方式解决:

Solve using a counter使用计数器求解

In the callback of the database query, before calling call.release , check the number of queries already processed, and only close the connection when the last product is being processed.在数据库查询的回调中,在调用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)
              }
          });
        });

Edit : There is also an issue with the res.json calls: inside the code in the question, res.json({ success: true }) is always executed, without waiting for the queries' execution results.编辑res.json调用也有一个问题:在问题的代码中, res.json({ success: true })总是被执行,而不等待查询的执行结果。 The modified code sample above calls res.json only once after the execution of all queries, this is the only place where res.json should be called.上面修改的代码示例在所有查询执行后只调用res.json一次,这是唯一应该调用res.json地方。 This implies modifying the client-side code so that it can handle an array of errors, rather than only one error.这意味着修改客户端代码,以便它可以处理一系列错误,而不仅仅是一个错误。

Solve by using a recursive function instead of for loop.通过使用递归函数而不是 for 循环来解决。

It is not a good practice to use for loops for the execution of asynchronous code.使用for循环来执行异步代码不是一个好习惯。 You might run into Maximum call stack size exceeded errors whenever the data volume gets too large.每当数据量变得太大时,您可能会遇到Maximum call stack size exceeded错误。

Instead, create a recursive function (eg updateDictItem ) to process one update query at a time.相反,创建一个递归函数(例如updateDictItem )以一次处理一个更新查询。 Read more about the asynchronous patterns in node.js in this article .本文中阅读有关 node.js 中异步模式的更多信息。

Other possible enhancements其他可能的改进

Rather than firing ten database queries, it is worth considering grouping all the updates in one MERGE update statement , otherwise doing all the updates in a TRANSACTION .与其触发十个数据库查询,不如考虑将所有更新分组在一个MERGE更新语句中,否则在TRANSACTION进行所有更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM