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

NodeJS使用mysql2插入后立即查询无结果的异常问题排查

问题根源

你的核心问题出在 pi 函数的异步逻辑处理上:

  • pi 函数里用 newArr.forEach 循环执行插入操作时,调用的是回调式的 db.query,这是异步操作,但你在循环结束后立刻调用了 resolve(),完全没等所有插入请求执行完成。
  • 这就导致 await pi() 看似执行完毕,实际上数据库里的 pacesetterIndex 数据还没全部写入,此时执行 insert 里的 q2 查询,自然查不到数据。只有当插入操作碰巧比查询快(比如首次启动时连接池空闲、响应快),才能查到结果,这就是你看到仅10%概率成功的原因。

另外 pi 函数还有两个错误处理漏洞:

  • 当查询 SELECT classID FROM pacesetterIndex 出错时,只给客户端返回了500状态,但 Promise 没有 reject,会导致 await pi() 一直挂起
  • 当查到已有数据返回409状态时,同样没有 resolve/reject,Promise 也会一直挂起

修复方案

1. 修复 pi 函数的异步等待逻辑

把每个插入操作包装成 Promise,用 Promise.all 等待所有插入完成后再 resolve:

const pi = async () => {
  return new Promise((resolve, reject) => {
    db.query(
      "SELECT classID FROM pacesetterIndex WHERE classID = ?",
      [classID],
      async function (err, result) {
        if (err) {
          res.status(500).send("Something went wrong");
          return reject(err);
        }

        if (result.length !== 0) {
          res.status(409).send("A pacesetter for this class already exists.");
          return resolve();
        } else {
          let parentArr = [
            {
              classID: classID,
              teacherID: teacherID,
              subjectID: subjectID,
              pacesetterList: pacesetterList,
              createdAt: createdAt,
            },
          ];

          let newArr = [];
          parentArr.forEach((parent) => {
            parent.pacesetterList.forEach((child) => {
              newArr.push({
                classID: parent.classID,
                teacherID: parent.teacherID,
                subjectID: parent.subjectID,
                startDate: child.startDate,
                endDate: child.endDate,
                objectives: child.objectives,
                createdAt: parent.createdAt,
              });
            });
          });

          // 把每个插入请求包装成Promise
          const insertPromises = newArr.map((data) => {
            return new Promise((insRes, insRej) => {
              db.query(
                "INSERT INTO pacesetterIndex SET classID = ?, teacherID = ?, subjectID = ?, startDate = ?, endDate = ?, objectives = ?, createdAt = ?;",
                [
                  data.classID,
                  data.teacherID,
                  data.subjectID,
                  data.startDate,
                  data.endDate,
                  data.objectives,
                  data.createdAt,
                ],
                (err) => err ? insRej(err) : insRes()
              );
            });
          });

          // 等待所有插入完成再resolve
          await Promise.all(insertPromises);
          resolve();
        }
      }
    );
  });
};

2. 可选:改用 mysql2 的 Promise API(更简洁)

mysql2 本身支持 Promise 风格调用,无需手动包装 Promise,代码更易维护:

const pi = async () => {
  try {
    const [result] = await db.promise().query(
      "SELECT classID FROM pacesetterIndex WHERE classID = ?",
      [classID]
    );

    if (result.length !== 0) {
      res.status(409).send("A pacesetter for this class already exists.");
      return;
    }

    let parentArr = [
      {
        classID: classID,
        teacherID: teacherID,
        subjectID: subjectID,
        pacesetterList: pacesetterList,
        createdAt: createdAt,
      },
    ];

    let newArr = [];
    parentArr.forEach((parent) => {
      parent.pacesetterList.forEach((child) => {
        newArr.push({
          classID: parent.classID,
          teacherID: parent.teacherID,
          subjectID: parent.subjectID,
          startDate: child.startDate,
          endDate: child.endDate,
          objectives: child.objectives,
          createdAt: parent.createdAt,
        });
      });
    });

    // 批量插入并等待完成
    const insertPromises = newArr.map(data => 
      db.promise().query(
        "INSERT INTO pacesetterIndex SET classID = ?, teacherID = ?, subjectID = ?, startDate = ?, endDate = ?, objectives = ?, createdAt = ?;",
        [data.classID, data.teacherID, data.subjectID, data.startDate, data.endDate, data.objectives, data.createdAt]
      )
    );
    await Promise.all(insertPromises);
  } catch (err) {
    res.status(500).send("Something went wrong");
    throw err;
  }
};

3. 修复 insert 函数的潜在问题

insert 函数里的 arr3.forEach 插入同样是异步无等待的,虽然不是当前问题的根源,但建议改成 Promise.all 确保所有插入完成:

const insert = async () => {
  try {
    const [arr1] = await db.promise().query(
      "SELECT studentID, classID FROM classStudent WHERE classID = ?;",
      [classID]
    );
    const [arr2] = await db.promise().query(
      "SELECT pacesetterID FROM pacesetterIndex WHERE classID = ?;",
      [classID]
    );

    let arr3 = [];
    for (let i = 0; i < arr1.length; i++) {
      for (let j = 0; j < arr2.length; j++) {
        arr3.push({ ...arr2[j], ...arr1[i] });
      }
    }

    console.log("Array 1", arr1.length);
    console.log("Array 2", arr2.length);
    console.log("Array 3", arr3.length);

    // 等待所有插入完成
    const insertPromises = arr3.map(data => 
      db.promise().query(
        "INSERT INTO pacesetterEntries SET pacesetterID = ?, classID = ?, studentID = ?;",
        [data.pacesetterID, data.classID, data.studentID]
      )
    );
    await Promise.all(insertPromises);
  } catch (err) {
    console.log(err);
  }
};

总结

修复后,pi 函数会等待所有插入操作完成后才会 resolve,确保 insert 函数执行时,pacesetterIndex 的数据已经完全写入数据库,q2 查询就能稳定返回结果了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:40:48