JavaScript使用Promise/async-await操作MySQL时无法等待查询完成
问题分析与解决方案
核心问题
你的代码存在几个关键问题导致异步流程失控:
- 重复执行
USE查询(连接配置里已指定database,无需手动执行) - 调用异步函数
sequentialQueries时未使用await,主程序不等待异步操作完成就继续执行 - 手动拼接SQL存在注入风险,且异步流程未统一管理
- 数据库连接未在所有操作完成后正确关闭
修正后的代码
const mysql = require('mysql'); const selectedDB = 'ItalianVerbs'; const str_VerbCols = "(infinitive, english, auxiliary, gerund, participle)"; // 创建连接,配置里已指定database,无需手动执行USE const g_con = mysql.createConnection({ host: 'localhost', user: 'root', password: 'Kl1n&on0per@', database: selectedDB }); // 封装mysql查询为通用Promise方法 function queryPromise(sql, params) { return new Promise((resolve, reject) => { g_con.query(sql, params, (err, res) => { if (err) reject(err); else resolve(res); }); }); } // 构建参数化INSERT查询(避免SQL注入) function buildInsertQuery(valList) { if (valList.length < 5) { console.error("[buildInsertQuery] 错误:插入行的参数数量不足"); return null; } // 使用?作为占位符,由mysql包自动处理参数转义 return { sql: `INSERT INTO Verb ${str_VerbCols} VALUES (?, ?, ?, ?, ?)`, params: valList }; } // 统一执行所有插入操作的函数 async function insertAllVerbs(verbList) { try { // 等待连接建立成功 await new Promise((resolve, reject) => { g_con.connect(err => { if (err) reject(err); else resolve(); }); }); console.log("数据库连接成功"); // 按顺序执行插入操作(如需并行可改用Promise.all) for (const verb of verbList) { const queryData = buildInsertQuery(verb); if (!queryData) continue; console.log(`*** 执行查询: ${queryData.sql}`, queryData.params); await queryPromise(queryData.sql, queryData.params); console.log(`已插入动词: ${verb[0]}`); } console.log("所有插入操作完成"); return 0; } catch (err) { console.error("操作出错:", err); return err; } finally { // 无论成功失败,最后关闭数据库连接 g_con.end(); console.log("数据库连接已关闭"); } } // 测试数据 const verbList = [ ["adorare", "adore", "avere", "adorando", "adorato"], ["abitare", "dwell", "avere", "abitando", "abitato"], ["abbassare", "let-down", "avere", "abbandonando", "abbandonato"] ]; // 启动执行,等待所有操作完成后再退出程序 insertAllVerbs(verbList) .then(result => { console.log("执行完成,退出程序"); process.exit(result === 0 ? 0 : 1); }) .catch(err => { console.error("执行失败:", err); process.exit(1); });
关键改进点
- 通用Promise封装:把
mysql.query封装成通用方法,避免重复编写异步逻辑 - 参数化查询:用
?占位符替代手动拼接字符串,彻底规避SQL注入风险 - 异步流程管控:用
for...of循环替代forEach(forEach无法等待异步操作),确保插入按顺序执行;若需并行执行可改用Promise.all - 连接生命周期管理:等待连接建立成功后再执行操作,所有任务完成后统一关闭连接
- 主程序等待机制:通过
then/catch等待所有异步操作完成后再退出,确保查询全部执行完毕
内容的提问来源于stack exchange,提问作者user55836
相关产品推荐
相关产品推荐

