Node.js+Express+MySQL连接池Promise化及错误处理咨询
Node.js + Express + MySQL连接池:Promise封装与错误处理优化方案
嘿,针对你用Node.js+Express+MySQL连接池的这套实现,我先帮你梳理下现有代码的问题,再给出几个实用的错误处理优化方案:
一、先修复基础Promise封装的核心漏洞
你当前的getConnection代码有个致命问题:获取到连接后没有调用resolve(connection),这会导致Promise永远处于pending状态,调用方永远拿不到连接。另外,错误信息最好保留原始错误对象,不要只转成字符串,这样后续能拿到错误码、堆栈等关键排查信息。
修复后的代码:
exports.getConnection = () => { return new Promise((resolve, reject) => { pool.getConnection((err, connection) => { if (err) { // 用Error对象包装,保留原始错误作为cause,方便后续排查 reject(new Error(`无法从连接池获取连接: ${err.message}`, { cause: err })); return; } // 必须resolve拿到的连接,否则Promise会一直挂起 resolve(connection); }); }); };
二、连接池层面的全局错误监听
连接池本身可能出现底层错误(比如数据库连接断开、创建连接超时),如果不监听这些错误,可能会导致未捕获异常终止进程。给连接池添加全局错误监听:
// 监听连接池全局错误 pool.on('error', (err) => { console.error('MySQL连接池全局错误:', err); // 针对常见错误类型做针对性处理 switch(err.code) { case 'PROTOCOL_CONNECTION_LOST': console.log('数据库连接已断开,尝试重新初始化连接池...'); // 这里可以根据你的逻辑重新创建连接池(如果需要) break; case 'ER_ACCESS_DENIED_ERROR': console.error('数据库权限验证失败,请检查账号密码'); break; default: console.error('未知连接池错误:', err); } });
三、Express全局错误处理中间件
确保所有路由中的数据库操作错误都能被统一捕获,避免进程崩溃,同时给客户端返回合理的错误响应:
注意:这个中间件必须放在所有路由定义之后!
app.use((err, req, res, next) => { // 打印完整错误日志(生产环境可以只打印关键信息) console.error('应用全局错误:', err); const isProduction = process.env.NODE_ENV === 'production'; // 根据环境返回不同的错误信息 res.status(err.statusCode || 500).json({ message: isProduction ? '服务器内部错误' : err.message, // 开发环境返回堆栈信息方便调试 ...(!isProduction && { stack: err.stack }), // 传递原始错误的原因(如果有的话) ...(err.cause && { cause: err.cause.message }) }); });
四、数据库操作中的连接释放与错误捕获
不管数据库操作成功还是失败,必须释放连接,否则会导致连接池耗尽,无法处理新请求。推荐用async/await结合try/catch/finally来实现:
async function getUsersList() { let connection; try { // 获取连接 connection = await getConnection(); // 执行查询 const [rows] = await connection.query('SELECT * FROM users WHERE is_active = ?', [1]); return rows; } catch (err) { console.error('查询用户列表失败:', err); // 可以在这里针对不同错误类型做重试、告警等操作 // 比如死锁错误(ER_LOCK_DEADLOCK)可以重试1-2次 if (err.code === 'ER_LOCK_DEADLOCK' && retryCount < 2) { retryCount++; return getUsersList(); } // 抛出错误让全局中间件处理 throw err; } finally { // 无论成功失败,都释放连接回池 if (connection) { connection.release(); } } }
五、进阶错误处理策略
- 错误分类处理:根据MySQL错误码(比如
ER_BAD_FIELD_ERROR表示字段不存在,ER_DUP_ENTRY表示唯一键冲突)返回对应HTTP状态码(400、409等),让客户端更清楚错误原因 - 重试机制:针对临时错误(连接超时、死锁)实现有限次数的重试,提升系统容错性
- 日志上报:把错误信息(包括请求上下文、错误堆栈)上报到日志系统(比如Winston、Bunyan),方便后续排查问题
内容的提问来源于stack exchange,提问作者zebullon
相关产品推荐
相关产品推荐

