JS中SQL查询回调内caracnamesecurity变量值异常问题求助
问题原因分析
这是典型的JavaScript循环中的闭包陷阱,核心问题出在var声明的变量作用域和异步回调的执行时机上:
var声明的caracnamesecurity是函数作用域变量,整个循环里共用同一个变量引用。connection.query是异步操作,它的回调函数不会立即执行,而是等SQL查询完成后才会触发。当所有回调开始执行时,外层的for循环已经完全跑完了,caracnamesecurity已经被更新为循环最后一次迭代的那个值(也就是texture),所以所有回调里打印的都是这个最后值。
解决方案
有几种简单的方式可以解决这个问题,推荐优先使用现代JS的写法:
1. 用let代替var声明变量
let是块级作用域,每次循环迭代都会创建一个新的变量绑定,回调函数会捕获当前迭代的那个变量值,而不是共用同一个引用:
var avisId = results.insertId if (typeof scoreAvis !== 'undefined') { // 把循环变量i也改成let,避免同样的问题 for (let i = 0; i < scoreAvis.length; i++) { if (scoreAvis[i].score > 0){ let caracnamesecurity = scoreAvis[i].caracname; let scoresecurity = scoreAvis[i].score; // 用模板字符串让SQL更易读 connection.query(`UPDATE avis SET ${caracnamesecurity}=${scoresecurity} WHERE avis.id=${avisId}`, function (error, results, fields) { if (!!error) { console.log("error avis"); } else { console.log("updated") } }); connection.query(`SELECT AVG(${caracnamesecurity}) FROM avis WHERE products_id=${req.body[0].id}`, function (error, results, fields) { console.log(results[0]) console.log(`${caracnamesecurity} f qsf qsd `) }); } } }
2. 使用forEach循环替代for循环
forEach的回调函数本身就是一个独立的作用域,每次迭代的变量都会被单独保留:
var avisId = results.insertId if (typeof scoreAvis !== 'undefined') { scoreAvis.forEach(item => { if (item.score > 0){ const caracnamesecurity = item.caracname; const scoresecurity = item.score; connection.query(`UPDATE avis SET ${caracnamesecurity}=${scoresecurity} WHERE avis.id=${avisId}`, function (error, results, fields) { if (!!error) { console.log("error avis"); } else { console.log("updated") } }); connection.query(`SELECT AVG(${caracnamesecurity}) FROM avis WHERE products_id=${req.body[0].id}`, function (error, results, fields) { console.log(results[0]) console.log(`${caracnamesecurity} f qsf qsd `) }); } }); }
额外提醒:避免SQL注入风险
你现在直接把变量拼接到SQL语句里,存在严重的SQL注入安全隐患!建议使用MySQL驱动提供的参数化查询方式,用??代替列名,?代替值:
// UPDATE的参数化写法 connection.query( "UPDATE avis SET ?? = ? WHERE avis.id = ?", [caracnamesecurity, scoresecurity, avisId], function(error, results) { if (error) { console.log("error avis"); } else { console.log("updated") } } ); // SELECT的参数化写法 connection.query( "SELECT AVG(??) FROM avis WHERE products_id = ?", [caracnamesecurity, req.body[0].id], function(error, results) { if (!error) { console.log(results[0]) console.log(`${caracnamesecurity} f qsf qsd `) } } );
参数化查询会自动处理转义,避免注入攻击,同时也让代码更规范。
内容的提问来源于stack exchange,提问作者user8283849
相关产品推荐
相关产品推荐

