Node.js调用API查询船只数据时交替返回结果问题求助
Node.js调用MySQL存储过程结果交替异常的解决方案
问题现象
新增条目(通过MySQL或Postman操作)后,按用户过滤检索boats条目时,结果交替出现:第一次正常返回全部数据,第二次无结果,第三次正常,第四次又无结果。
已知信息
- 直接在MySQL中调用存储过程
sp_get_boat_summary始终返回正确数据 - 等待4-5分钟后API自动恢复正常
- 重启nodemon服务后API也能正常响应所有请求
现有代码
数据库连接文件(database.js)
const mysql = require('mysql'); //const mysql = require('mysql2'); const util = require ('util'); const pool = mysql.createPool({ connectionLimit: 10, host: 'x.xxx.xx.xxx', user: 'xxxxx-xxx', password: 'xxxxxxxxxxxx', database: 'xxxxxxxxxxxx', port: 3306, queueLimit: 1000, }); pool.getConnection((err,connection)=> { if(err) throw err; console.log('Database connected successfully'); connection.release(); }); module.exports = pool;
控制器文件(trxController.js)
const trxModel = require('../models/trxModels'); // Async const getboatsummaryAsync = util.promisify(trxModel.boatsummary); exports.boatsummary = async (req, res) => { try { const input = req.params.usercode; const response_data = await getboatsummaryAsync(input) // Call user model if (!response_data){ return res.status(404).json({ error: 'User not found in DB' }); } return res.status(200).json(response_data); } catch (error) { console.log('Error in boatSummary: ', error) return res.status(500).json({ error: 'Internal server error' }); } };
模型文件(trxModels.js)
const db = require('../config/database.js'); const db = require('../config/database.js'); static async boatsummary(input, callback) { const sql = 'CALL sp_get_boat_summary(?);'; await db.query(sql, [input], function (error, results) { console.log(input); if (error) return callback(error, null); const formattedResults = results[0].map((row) => ({ ...row })); return callback(null,formattedResults); }); }
问题根源
- 异步逻辑混乱:模型中
boatsummary方法标记为async,但内部使用回调式的db.query,await对回调方法无效,导致util.promisify处理后出现回调状态异常。 - 重复引入数据库连接:模型文件中重复
require数据库连接,可能导致连接实例冲突。 - 连接池状态残留:存储过程调用后,连接池中的连接可能残留未重置的状态,被复用时返回空结果;当连接被自动回收重置(等待超时)或服务重启后,状态恢复正常,因此出现交替现象。
修复方案
方案1:修正异步逻辑(基于原mysql库)
修改模型文件
移除重复的db引入,改用util.promisify处理db.query而非整个方法:
const db = require('../config/database.js'); const util = require('util'); // 绑定db上下文,确保query方法能正确使用连接池 const queryAsync = util.promisify(db.query).bind(db); static async boatsummary(input) { const sql = 'CALL sp_get_boat_summary(?);'; const results = await queryAsync(sql, [input]); return results[0].map(row => ({ ...row })); }
修改控制器文件
无需再手动promisify模型方法,直接调用异步方法:
const trxModel = require('../models/trxModels'); exports.boatsummary = async (req, res) => { try { const input = req.params.usercode; const response_data = await trxModel.boatsummary(input); // 空数组也需要判断,避免无结果时误判 if (!response_data || response_data.length === 0){ return res.status(404).json({ error: 'User not found in DB' }); } return res.status(200).json(response_data); } catch (error) { console.log('Error in boatSummary: ', error) return res.status(500).json({ error: 'Internal server error' }); } };
方案2:改用mysql2(推荐,原生支持Promise)
修改数据库连接文件
切换到mysql2的Promise版本,避免util.promisify的潜在问题:
const mysql = require('mysql2/promise'); const pool = mysql.createPool({ connectionLimit: 10, host: 'x.xxx.xx.xxx', user: 'xxxxx-xxx', password: 'xxxxxxxxxxxx', database: 'xxxxxxxxxxxx', port: 3306, queueLimit: 1000, }); // 测试连接(可选) (async () => { try { const connection = await pool.getConnection(); console.log('Database connected successfully'); connection.release(); } catch (err) { console.error('Database connection failed:', err); process.exit(1); } })(); module.exports = pool;
修改模型文件
直接使用Promise风格的query方法:
const db = require('../config/database.js'); static async boatsummary(input) { const sql = 'CALL sp_get_boat_summary(?);'; // mysql2的query返回[结果集, 字段信息],取第一个元素 const [results] = await db.query(sql, [input]); return results[0].map(row => ({ ...row })); }
控制器文件同方案1的修改
验证
修复后,新增条目后多次调用API,应能稳定返回正确结果,不再出现交替无结果的情况。
内容的提问来源于stack exchange,提问作者Guillermo Bastian
相关产品推荐
相关产品推荐

