Discord.js机器人SQL查询异步问题:代码未等待数据库返回结果
解决Discord.js机器人数据库查询异步顺序问题
你的问题核心在于mysql模块的con.query是异步回调式的API——当前代码里,数据库查询还没返回结果,后面的console.log和命令判断逻辑就已经执行了,导致prefix还是undefined,前缀校验自然失效。
你不想用.then()嵌套的思路是对的,async/await确实是更优雅的解决方案,但需要把异步的查询操作转换成可以被await的Promise形式(原生mysql的回调API不支持直接await)。下面是具体的解决方法:
方法1:手动将query包装为Promise
先写一个工具函数,把con.query包装成返回Promise的形式,这样就能用await等待结果:
const { Client, Attachment, RichEmbed } = require('discord.js'); const client = new Client(); const mysql = require("mysql"); const config = require("./config.json") var con = mysql.createConnection({ host: 'localhost', user: 'root', password: '', database: 'botdb' }) // 包装query为Promise函数,方便用await调用 function runQuery(sql, params) { return new Promise((resolve, reject) => { con.query(sql, params, (err, rows) => { if (err) reject(err); else resolve(rows); }); }); } client.on("ready", () => { console.log("I'm ready") }) // 将message事件处理函数标记为async,这样内部才能用await client.on("message", async message => { if (message.author.bot) return; if (message.channel.type === 'dm') return; let msg = message.content.split(" "); let command = msg[0]; let prefix; try { // 用await等待数据库查询完成,拿到结果后再执行后续逻辑 const rows = await runQuery(`SELECT * FROM serversettings WHERE ServerID = ?`, [message.guild.id]); prefix = rows[0].Prefix; console.log(prefix); // 现在prefix已经有值了,执行命令判断 console.log(`Prefix: ${prefix}, Command: ${command}`); if (command === `${prefix}examplecommand`) { // Do something message.channel.send("示例命令执行成功!"); } // 其他依赖prefix的代码也可以放在这里 } catch (err) { console.error("数据库查询出错:", err); // 可以在这里添加错误处理,比如给用户发送提示 } }) client.login(config.token); // 记得补充登录代码
方法2:改用支持Promise的mysql库(更推荐)
原生mysql模块是回调式的,改用mysql2的Promise版本会更简洁,不需要手动包装:
- 先安装依赖:
npm install mysql2 - 修改代码如下:
const { Client, Attachment, RichEmbed } = require('discord.js'); const client = new Client(); const mysql = require("mysql2/promise"); // 引入promise版本 const config = require("./config.json") // 创建连接池(比单个连接更稳定,适合机器人长期运行) const pool = mysql.createPool({ host: 'localhost', user: 'root', password: '', database: 'botdb' }) client.on("ready", () => { console.log("I'm ready") }) client.on("message", async message => { if (message.author.bot) return; if (message.channel.type === 'dm') return; let msg = message.content.split(" "); let command = msg[0]; let prefix; try { // 直接await pool.query,返回结果是[rows, fields],我们只需要rows const [rows] = await pool.query(`SELECT * FROM serversettings WHERE ServerID = ?`, [message.guild.id]); prefix = rows[0].Prefix; console.log(prefix); console.log(`Prefix: ${prefix}, Command: ${command}`); if (command === `${prefix}examplecommand`) { message.channel.send("示例命令执行成功!"); } } catch (err) { console.error("数据库查询出错:", err); } }) client.login(config.token);
关键注意事项
- 必须标记事件处理函数为
async:await只能在async函数内部使用,这是你之前用了async/await却没生效的核心原因之一。 - 修复SQL注入风险:我把你原来的
${message.guild.id}改成了参数化查询的?和参数数组——这能防止恶意用户构造特殊ID注入恶意SQL,是必须的安全措施。 - 错误处理:用
try/catch包裹await代码,避免数据库查询出错导致机器人崩溃。
现在你的代码会先等待数据库返回前缀,再执行后续的命令判断,日志顺序会符合预期,前缀校验也能正常工作了。
内容的提问来源于stack exchange,提问作者Thrith
相关产品推荐
相关产品推荐

