Node.js for循环中执行MySQL查询 外部count统计值为0问题求助
问题根因
- 核心是Node.js异步IO的执行逻辑:
connection.query属于异步非阻塞方法,调用后不会等待数据库返回结果就会立刻执行后续代码。同步执行的for循环会瞬间把所有查询请求发出去,紧接着就执行了循环外的console.log(counts),此时所有查询的回调函数都还没有被触发,counts还是初始值0,所以始终打印0。 - 潜在风险:原代码直接拼接SQL字符串,存在SQL注入漏洞,必须改用参数化查询。
- 额外隐藏坑:原循环用
var声明迭代变量i,如果回调中用到i会出现变量提升导致的取值错误,建议改用let或者for...of遍历。
修复方案
方案1:单次查询优化(推荐,性能最优)
不需要循环发起多次数据库请求,直接用IN条件一次查询所有存在的序列号,再对比原数组统计不存在的数量,性能远高于循环查询:
// 建议使用mysql2/promise库以支持async/await语法 const mysql = require('mysql2/promise'); // 推荐使用连接池代替单连接,性能和稳定性更好 const pool = mysql.createPool({ host: '你的数据库地址', user: '数据库用户名', password: '数据库密码', database: '数据库名' }); app.get('/stock_outward', async function (req, res) { try { const serial_values = "SV-K8B22490,SV-K8B22491,SV-K8B22492,SV-K8B22493,SV-K8B22494,SV-K8B22495,SV-K8B22496,SV-K8B22497,SV-K8B22498,SV-K8B22499"; const serial_arys = serial_values.split(","); // 一次查询拿到所有存在的序列号 const [existsResults] = await pool.query('SELECT s_no FROM stock_inward WHERE s_no IN (?)', [serial_arys]); // 提取存在的序列号列表 const existsSerials = existsResults.map(item => item.s_no); // 过滤出不存在的序列号,统计数量 const notExistsSerials = serial_arys.filter(serial => !existsSerials.includes(serial)); const notExistsCount = notExistsSerials.length; console.log('不存在的序列号数量:', notExistsCount); // 返回响应给前端 res.json({ notExistsCount: notExistsCount, notExistsList: notExistsSerials }); } catch (error) { console.error('查询失败:', error); res.status(500).json({ error: '服务器内部错误' }); } });
方案2:async/await 循环查询(适合需要单独处理每个序列号查询结果的场景)
如果确实需要逐个处理每个序列号的查询逻辑,可以用async/await保证所有查询执行完成后再统计结果:
const mysql = require('mysql2/promise'); const pool = mysql.createPool({ // 连接配置同方案1 }); app.get('/stock_outward', async function (req, res) { try { const serial_values = "SV-K8B22490,SV-K8B22491,SV-K8B22492,SV-K8B22493,SV-K8B22494,SV-K8B22495,SV-K8B22496,SV-K8B22497,SV-K8B22498,SV-K8B22499"; const serial_arys = serial_values.split(","); let existsCount = 0; for (const serial of serial_arys) { // 等待当前查询执行完成再进入下一次循环 const [results] = await pool.query('SELECT * FROM stock_inward WHERE s_no = ?', [serial]); if (results.length > 0) { existsCount++; } } // 所有查询完成后统计不存在的数量 const notExistsCount = serial_arys.length - existsCount; console.log('不存在的序列号数量:', notExistsCount); res.json({ notExistsCount: notExistsCount }); } catch (error) { console.error('查询失败:', error); res.status(500).json({ error: '服务器内部错误' }); } });
方案3:回调写法兼容(无需改造为async/await)
如果要保留原回调写法,需要增加计数器判断所有查询是否全部执行完成:
app.get('/stock_outward', function (req, res) { const serial_values = "SV-K8B22490,SV-K8B22491,SV-K8B22492,SV-K8B22493,SV-K8B22494,SV-K8B22495,SV-K8B22496,SV-K8B22497,SV-K8B22498,SV-K8B22499"; const serial_arys = serial_values.split(","); const total = serial_arys.length; let existsCount = 0; let doneCount = 0; // 记录已完成的查询数 for (let i = 0; i < total; i++) { // 参数化查询避免注入 connection.query('SELECT * FROM stock_inward WHERE s_no = ?', [serial_arys[i]], function (error, results, fields) { doneCount++; if (error) throw error; if (results.length > 0) { existsCount++; } // 所有查询都执行完成后再统计结果 if (doneCount === total) { const notExistsCount = total - existsCount; console.log('不存在的序列号数量:', notExistsCount); res.json({ notExistsCount: notExistsCount }); } }); } });
内容的提问来源于stack exchange,提问作者Kalaiarasan
相关产品推荐
相关产品推荐

