【问题标题】:How to solve nodejs uncaughtException: Connection already released error and MaxListenersExceededWarning?如何解决nodejs uncaughtException:连接已释放错误和MaxListenersExceededWarning?
【发布时间】:2020-06-26 17:56:34
【问题描述】:

我正在构建一个快速服务器来接收来自我的反应前端的请求(一个包含 10 个项目的字典),然后将数据保存到数据库中。下面是我的代码。我发现我的代码有效,并且查询确实将记录保存回 Db。但是在每个 for 循环中,这个错误都会在 server.xml 中返回。是什么导致此错误和 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】:

    正在从池中检索一个连接 (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)
                  }
              });
            });
    

    编辑res.json 调用还有一个问题:在问题的代码中,res.json({ success: true }) 总是被执行,而不是等待查询的执行结果。上面修改后的代码示例在所有查询执行后只调用一次res.json,这是唯一应该调用res.json 的地方。这意味着修改客户端代码,使其可以处理一系列错误,而不仅仅是一个错误。

    使用递归函数代替 for 循环求解。

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

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

    其他可能的增强功能

    与其触发十个数据库查询,不如考虑将所有更新分组到一个 MERGE update statement 中,否则将所有更新都放在一个 TRANSACTION 中。

    【讨论】:

    • 感谢您的回复。但是如果我想将每个查询结果推送到列表中呢?如何解决只推送最后一个查询结果?
    • “将每个查询推送到“列表”是什么意思?是“执行数据库中的每个更新查询”吗?
    • 对不起,让我澄清一下。我的意思是当少数查询有错误时,我想通过 err_msg.push({'errno':err.errno, 'sql_message':err.sqlMessage});将返回的错误消息推送到列表中>
    • 我明白了。最后的return res.json({ success: true }) 应该被删除。我更新了答案以显示如何解决这个问题。
    猜你喜欢
    • 2019-01-06
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    • 2012-05-20
    • 1970-01-01
    • 2018-03-19
    相关资源
    最近更新 更多