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
相关产品推荐
相关产品推荐

