Node.js服务器频繁触发未处理'error'事件:MySQL连接丢失问题
Node.js MySQL连接丢失错误分析与解决
错误日志
events.js:174 throw er; // Unhandled 'error' event ^ Error: Connection lost: The server closed the connection. at Protocol.end (/home/user/nodejs/chat/node_modules/mysql/lib/protocol/Protocol.js:112:13) at Socket.<anonymous> (/home/user/nodejs/chat/node_modules/mysql/lib/Connection.js:94:28) at Socket.<anonymous> (/home/user/nodejs/chat/node_modules/mysql/lib/Connection.js:526:10) at Socket.emit (events.js:203:15) at endReadableNT (_stream_readable.js:1145:12) at process._tickCallback (internal/process/next_tick.js:63:19) Emitted 'error' event at: at Connection._handleProtocolError (/home/user/nodejs/chat/node_modules/mysql/lib/Connection.js:423:8) at Protocol.emit (events.js:198:13) at Protocol._delegateError (/home/user/nodejs/chat/node_modules/mysql/lib/protocol/Protocol.js:398:10) at Protocol.end (/home/user/nodejs/chat/node_modules/mysql/lib/protocol/Protocol.js:116:8) at Socket.<anonymous> (/home/user/nodejs/chat/node_modules/mysql/lib/Connection.js:94:28) [... lines matching original stack trace ...] at process._tickCallback (internal/process/next_tick.js:63:19)
错误原因
- MySQL服务器主动断开空闲连接:默认配置中
wait_timeout和interactive_timeout均为8小时,连接长时间无活动会被服务器判定为闲置并断开。 - 网络不稳定:服务器与数据库之间的网络波动、防火墙拦截、路由中断等,都可能导致连接意外中断。
- 未处理连接错误事件:代码未监听Connection的
error事件,一旦连接出错就会抛出未捕获异常,直接导致进程崩溃。 - 连接池配置不合理:使用连接池但未配置健康检查,池内连接被MySQL断开后,客户端仍尝试复用无效连接,引发报错。
解决方法
- 监听连接错误事件:给连接或连接池添加
error事件监听,既避免进程崩溃,还能在连接断开时触发自动重连逻辑。const connection = mysql.createConnection(/* 你的数据库配置 */); connection.on('error', (err) => { console.error('MySQL连接出错:', err); if (err.code === 'PROTOCOL_CONNECTION_LOST') { // 自定义重连函数恢复连接 reconnect(); } else { throw err; } }); - 使用连接池并开启健康检查:用连接池替代单连接管理,同时开启
testOnBorrow选项,确保获取连接前先验证其可用性。const pool = mysql.createPool({ host: 'localhost', user: 'your_user', password: 'your_pwd', database: 'chat', testOnBorrow: true, // 借连接前检测有效性 connectTimeout: 10000, connectionLimit: 10, // 根据业务调整连接数上限 waitForConnections: true }); - 调整MySQL超时参数:如果业务需要长连接,可适当延长
wait_timeout和interactive_timeout(注意不要设置过长,避免连接数过载)。SET GLOBAL wait_timeout = 28800; -- 8小时,按需调整 SET GLOBAL interactive_timeout = 28800; - 定期发送心跳保活:每隔一段时间执行简单SQL(如
SELECT 1),保持连接活跃,避免被MySQL判定为闲置断开。// 每5分钟发送一次心跳 setInterval(() => { connection.query('SELECT 1', (err) => { if (err) console.error('心跳检测失败:', err); }); }, 300000); - 排查网络问题:检查服务器与数据库之间的网络稳定性,确认防火墙未拦截数据库端口,排除网络层面的连接中断因素。
内容的提问来源于stack exchange,提问作者Cain Nuke
相关产品推荐
相关产品推荐

