You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何同步执行MySQL查询以得到预期输出结果?

解决Node.js MySQL异步查询导致输出顺序不符的问题

问题描述

我有如下代码:

app.get('/showtable1', (req, res) => { 
  console.log("yo ho"); 
  mysqlconnection.query('SELECT d_name FROM datacenters', (err, rows, fields) => { 
    if (!err) { 
      var array = []; 
      var tier = ['Class 0','Class 1','Class 2','Class 3']; 
      var str = ''; 
      Object.keys(rows).forEach(function(key) { 
        var row = rows[key]; 
        array.push(row.d_name); 
      }); 
      for( var i = 0 ; i<array.length ; i++) { 
        str += '<tr><td>'+array[i]+'</td>'; 
        console.log('sfsf'); 
        for (var j=0 ; j< tier.length ; j++) { 
          let query1 = "SELECT * FROM `datacenters` WHERE d_name = '"+array[i]+"' AND d_tiers LIKE '%"+tier[j]+"%'" 
          mysqlconnection.query(query1,(err,rows) => { 
            if(!err) { 
              if(rows.length !=0) { 
                console.log(1); 
              } else { 
                console.log(0); 
              } 
            } 
          }); 
        } 
      } 
      res.send(rows); 
    } else console.log(err); 
  }) 
});

当前代码输出为:

yo ho
sfsf
sfsf
sfsf
1 1 0 0
1 1 1 0
1 1 1 0

但我需要的输出顺序是:

yo ho
sfsf
1 1 0 0
sfsf
1 1 1 0
sfsf
1 1 1 0

当前输出顺序不符是因为代码异步执行,我需要将其改为同步执行,请问该如何实现?


解决方案

没错,问题根源就是Node.js中MySQL的查询是异步回调模式,内层的tier查询会在外层循环的sfsf全部打印完之后才陆续返回结果。要实现你要的顺序,最优雅的方式是用Promise + async/await把异步操作转换成同步风格的代码,这也是现在Node.js处理异步逻辑的标准做法。

1. 先把MySQL查询包装成Promise

原生的mysqlconnection.query是回调风格,我们先把它封装成返回Promise的函数,这样才能用await等待执行完成:

// 封装Promise版的查询函数
function queryPromise(sql, params = []) {
  return new Promise((resolve, reject) => {
    mysqlconnection.query(sql, params, (err, rows) => {
      if (err) reject(err);
      else resolve(rows);
    });
  });
}

2. 用async/await重构路由逻辑

把路由的处理函数改成async函数,然后在需要等待查询结果的地方加上await,这样代码就会按顺序执行:

app.get('/showtable1', async (req, res) => { 
  try {
    console.log("yo ho"); 
    // 等待第一个查询完成,拿到所有数据中心名称
    const rows = await queryPromise('SELECT d_name FROM datacenters');
    // 用map简化数组生成,比forEach更简洁
    const array = rows.map(row => row.d_name);
    const tier = ['Class 0','Class 1','Class 2','Class 3']; 
    let str = ''; 

    for( let i = 0 ; i<array.length ; i++) { 
      str += '<tr><td>'+array[i]+'</td>'; 
      console.log('sfsf'); 
      // 逐个等待每个tier的查询完成,保证顺序
      for (let j=0 ; j< tier.length ; j++) { 
        // 这里改成参数化查询,避免SQL注入风险
        const resultRows = await queryPromise(
          'SELECT * FROM `datacenters` WHERE d_name = ? AND d_tiers LIKE ?',
          [array[i], `%${tier[j]}%`]
        );
        console.log(resultRows.length !== 0 ? 1 : 0);
      }
      // 可选:每个数据中心的结果打印完后换行,让输出更清晰
      console.log('');
    } 
    res.send(rows); 
  } catch (err) {
    console.error(err);
    // 错误时给客户端返回500状态码和提示
    res.status(500).send('服务器内部错误');
  }
});

重要提醒:避免SQL注入

你原来的代码直接把变量拼接到SQL语句里,这存在严重的SQL注入风险。上面的代码已经改成了参数化查询,MySQL会自动处理参数的转义,彻底避免这个问题,这是生产环境必须注意的点。

修改之后,代码就会严格按照你期望的顺序执行:打印sfsf之后,等待该数据中心的4个tier查询依次完成并输出1/0,再进入下一个循环打印sfsf,以此类推。


内容的提问来源于stack exchange,提问作者amar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:25:21