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

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版本会更简洁,不需要手动包装:

  1. 先安装依赖:npm install mysql2
  2. 修改代码如下:
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);

关键注意事项

  1. 必须标记事件处理函数为async:await只能在async函数内部使用,这是你之前用了async/await却没生效的核心原因之一。
  2. 修复SQL注入风险:我把你原来的${message.guild.id}改成了参数化查询的?和参数数组——这能防止恶意用户构造特殊ID注入恶意SQL,是必须的安全措施。
  3. 错误处理:用try/catch包裹await代码,避免数据库查询出错导致机器人崩溃。

现在你的代码会先等待数据库返回前缀,再执行后续的命令判断,日志顺序会符合预期,前缀校验也能正常工作了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:15:45