如何解决nodejs uncaughtException: Connection already released 错误和MaxListenersExceededWarning?
How to solve nodejs uncaughtException: Connection already released error and MaxListenersExceededWarning?
我正在构建一个快速服务器来接收来自我的反应前端的请求(一个包含 10 个项目的字典),然后将数据保存到数据库中。下面是我的代码。我发现我的代码可以正常工作,并且查询确实将记录保存回了 Db。但是在每个 for 循环中,这个错误都会在 server.导致此错误和 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
正在从池中检索一个连接 (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)
}
});
});
Edit: 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, otherwise doing all the updates in a TRANSACTION
。
我正在构建一个快速服务器来接收来自我的反应前端的请求(一个包含 10 个项目的字典),然后将数据保存到数据库中。下面是我的代码。我发现我的代码可以正常工作,并且查询确实将记录保存回了 Db。但是在每个 for 循环中,这个错误都会在 server.导致此错误和 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
正在从池中检索一个连接 (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)
}
});
});
Edit: res.json
调用也有问题:在问题的代码里面,res.json({ success: true })
一直执行,没有等待查询的执行结果。上面修改后的代码示例仅在所有查询执行后调用一次 res.json
,这是唯一应该调用 res.json
的地方。这意味着修改客户端代码,使其可以处理一系列错误,而不是仅处理一个错误。
使用递归函数代替 for 循环求解。
使用 for
循环执行异步代码不是一个好习惯。每当数据量太大时,您可能 运行 进入 Maximum call stack size exceeded
错误。
相反,创建一个递归函数(例如 updateDictItem
)来一次处理一个更新查询。在 this article.
其他可能的增强功能
与其触发十个数据库查询,不如考虑将所有更新分组为一个 MERGE
update statement, otherwise doing all the updates in a TRANSACTION
。