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

Node.js map遍历MySQL查询发推仅单次执行问题

代码核心问题说明
  • 异步流程完全失控,没有任何等待逻辑:
    1. 外层array.items.map是同步遍历,只会瞬间把所有SQL查询请求提交给mysql驱动,完全不会等待查询执行、发推文等后续异步流程跑完。如果是单次执行的脚本,在第一个查询对应的发推操作完成后,Node.js事件循环检测不到被持有的待执行任务,会直接退出进程,剩下的查询、发推任务根本没机会执行。
    2. 你传给con.query的虽然是带async的回调,但mysql驱动本身不识别回调返回的Promise,调用完回调就认为本次查询处理结束,根本不会等回调里的await sendTweet执行完成。
    3. 内层遍历查询结果用result.map传入async函数时,同样没有用await或Promise.all等待sendTweet异步任务执行,这些发推任务相当于“悬空”的Promise,没有任何地方等待其执行结果,很容易被中断。
  • 存在SQL注入风险:直接把item.country字符串拼接到SQL语句中,一旦参数包含双引号、SQL语句片段等特殊内容,会直接触发SQL报错,甚至引发数据泄露、篡改风险。
  • 错误处理逻辑失效:在mysql查询回调里直接throw err,这个错误抛出在异步回调上下文,不会被内层的try/catch捕获,会直接触发进程未捕获异常崩溃,只要某一条SQL查询报错,整个程序直接终止,后续所有任务都不会执行。
  • 单连接查询冲突风险:如果使用的是单个mysql连接实例,同步遍历瞬间提交多个查询,虽然驱动内部会做排队,但没有等待逻辑的情况下很容易出现连接状态混乱、结果匹配错位的问题。
修正方案

首先推荐把mysql连接切换为Promise风格(比如使用mysql2/promise初始化连接),用for...of循环做串行遍历,确保每一步异步操作都被正确等待,同时改用参数化查询避免注入风险,参考代码如下:

// 前置:使用mysql2/promise初始化数据库连接,替代原有回调风格的con实例
async function runBatchTweetTask() {
  // 串行遍历所有目标国家,避免异步任务悬空
  for (const item of array.items) {
    // 参数化查询,?作为占位符传入参数,彻底避免SQL注入
    const [userList] = await con.query(
      'SELECT username FROM users WHERE country = ?',
      [item.country]
    );
    console.log(userList);

    if (!userList.length) continue;

    // 串行给当前国家匹配到的所有用户发推文,也可根据需求加并发控制
    for (const user of userList) {
      try {
        await sendTweet(`Hello ${user.username}, your selected country is ${item.country}`);
      } catch (error) {
        // 单条推文发送失败只记录日志,不中断整个批量任务
        console.error('发推失败:', error.body);
      }
    }
  }
}

// 顶层执行任务,统一捕获全局异常
runBatchTweetTask()
  .catch(err => {
    console.error('批量发推任务异常终止:', err);
    process.exit(1);
  })
  .finally(() => {
    // 任务结束后记得关闭数据库连接
    con.end();
  });

如果需要提升发推效率,可以把同个国家下的用户发推任务用Promise.all做并发执行,注意控制并发数量,避免短时间请求过多触发推特接口限流。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:57:21