Express JS 抽取SQL查询至独立文件后遇数据库超时问题求助
问题分析与修复方案
核心问题
你的代码超时根本原因是异步逻辑的时序错误:
doQuery是同步函数,但mysql的connect、query、end都是异步操作,函数会直接跳到最后一行返回504超时结果,完全没等异步回调执行。- 直接写在路由里能运行,是因为路由回调本身是异步上下文,异步操作的回调能正确触发响应;但抽成独立函数后,同步返回的永远是504,回调里的
return对外层函数毫无意义。 connection.connect后显示disconnected,是因为你在同步代码里立刻查看状态,此时连接还没建立完成,而且你没等connect结束就直接执行query和end,导致连接还没就绪就被关闭,自然查不到数据也没错误日志(错误回调还没触发,函数就已经返回了)。
修复方案
方案1:用Promise封装异步逻辑
把doQuery改成返回Promise,路由用async/await等待结果:
修改SQL工具文件:
var mysql = require('mysql'); const connectionData = { host: 'localhost', user: 'root', password: '****', database: 'app' }; module.exports = { doQuery: function (query) { return new Promise((resolve) => { const connection = mysql.createConnection(connectionData); connection.connect(error => { if (error) { console.log(error); resolve({ status: 502, data: {error: {code: 502, message: "Database connection error."}} }); connection.end(); return; } connection.query(query, (error, results) => { // 先关闭连接再处理结果 connection.end(endError => { if (endError) { console.log(endError); resolve({ status: 502, data: {error: {code: 502, message: "Database connection error."}} }); return; } if (error) { console.log(error); resolve({ status: 500, data: {error: {code: 500, message: "Internal server error"}} }); } else if (results.length) { resolve({ status: 200, data: {data: results} }); } else { resolve({ status: 404, data: {error: {code: 404, message: "Not Found"}} }); } }); }); }); }); } }
修改路由代码:
router.get('/products', async function (req, res, next) { const response = await sqlHandler.doQuery('SELECT * FROM product'); return res.status(response.status).json(response.data); });
方案2:使用连接池(更推荐)
频繁创建销毁连接会损耗性能,用连接池可以复用连接,还能省去手动管理连接开闭的麻烦:
修改SQL工具文件:
var mysql = require('mysql'); const pool = mysql.createPool({ host: 'localhost', user: 'root', password: '****', database: 'app', connectionLimit: 10 // 根据业务调整连接数上限 }); module.exports = { doQuery: function (query) { return new Promise((resolve) => { pool.query(query, (error, results) => { if (error) { console.log(error); resolve({ status: 500, data: {error: {code: 500, message: "Internal server error"}} }); return; } if (results.length) { resolve({ status: 200, data: {data: results} }); } else { resolve({ status: 404, data: {error: {code: 404, message: "Not Found"}} }); } }); }); } }
路由代码和方案1一致,用async/await调用即可。
关键提醒
- 异步回调里的
return无法返回给外层同步函数,必须用Promise、回调传参或者async/await来处理时序。 - 永远要等待异步操作完成后再处理结果,不能跳过异步步骤直接返回。
- 连接池是生产环境的最优选择,能有效提升数据库操作的性能和稳定性。
内容的提问来源于stack exchange,提问作者radek wilo
相关产品推荐
相关产品推荐

