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

Node.js自定义MySQL函数返回undefined问题求助

问题根源:异步操作的返回值处理错误

你的所有数据库操作函数返回undefined,核心原因是**mysql.query是异步操作**——你在回调函数里写的return true/false,只会返回给回调函数本身,而外层的数据库函数(比如checkGuild)在调用mysql.query后会立刻执行完毕,默认返回undefined,根本拿不到回调里的结果。

另外还有两个小问题需要注意:

  1. 部分函数用字符串拼接SQL语句,存在SQL注入风险(比如addGuild),应该统一用参数占位符(就像你在checkVip里做的那样)。
  2. checkVip里的JSON.parse(result)是多余的,mysql.query返回的result已经是解析好的对象数组。

解决方案:用Promise+Async/Await处理异步流程

我们需要把所有数据库函数改成返回Promise,然后在Discord命令代码中用async/await等待异步操作完成,这样就能拿到正确的返回值。

1. 修改数据库操作文件(database.js)

把每个函数都用Promise包裹,统一处理异步逻辑和错误:

var MySql = require('mysql');
var mysql = MySql.createConnection({
 host: process.env.DB_IP,
 user: process.env.DB_USER,
 password: process.env.DB_PASS,
 database: "gamezone_3tar"
});
mysql.connect(function(err){
 if (err) throw err;
 console.log('MySql Connection Successfully!');
});

module.exports = {
 checkGuild: function(gid){
  return new Promise((resolve, reject) => {
    // 用参数占位符避免SQL注入
    var sql = "SELECT * FROM GUILDS WHERE `gid` = ?";
    mysql.query(sql, [gid], function (err, result) {
      if (err) reject(err);
      // 判断查询结果是否有数据,返回布尔值
      resolve(result.length > 0);
    });
  });
 },
 addGuild: function(gid, gname, gowner){
  return new Promise((resolve, reject) => {
    var sql = "INSERT INTO GUILDS(`gid`, `gname`, `gOwner`) VALUES (?, ?, ?)";
    mysql.query(sql, [gid, gname, gowner], function (err, result) {
      if (err) reject(err);
      resolve(true);
    });
  });
 },
 checkVip: function(type, id){
  return new Promise((resolve, reject) => {
    let sql;
    if(type == 'guild') sql = 'SELECT vip FROM GUILDS WHERE `gid` = ?';
    else if(type == 'user') sql = 'SELECT vip FROM USERS WHERE `uid` = ?';
    
    mysql.query(sql, [id], function(err, result){
      if (err) reject(err);
      // 没找到对应记录时返回false
      if (!result[0]) resolve(false);
      // 直接判断vip字段的值
      resolve(result[0].vip === 'true');
    });
  });
 },
 addVip: function(type, id){
  return new Promise((resolve, reject) => {
    let sql;
    if(type == 'guild') sql = "UPDATE GUILDS SET vip = 'true' WHERE `gid` = ?";
    else if(type == 'user') sql = "UPDATE USERS SET vip = 'true' WHERE `uid` = ?";
    
    mysql.query(sql, [id], function(err, result){
      if (err) reject(err);
      resolve(true);
    });
  });
 },
 removeVip: function(type, id){
  return new Promise((resolve, reject) => {
    let sql;
    if(type == 'guild') sql = "UPDATE GUILDS SET vip = 'false' WHERE `gid` = ?";
    else if(type == 'user') sql = "UPDATE USERS SET vip = 'false' WHERE `uid` = ?";
    
    mysql.query(sql, [id], function(err, result){
      if (err) reject(err);
      resolve(true);
    });
  });
 },
 removeGuild: function(gid){
  return new Promise((resolve, reject) => {
    var sql = "DELETE FROM GUILDS WHERE `gid` = ?";
    mysql.query(sql, [gid], function(err, result){
      if (err) reject(err);
      resolve(true);
    });
  });
 }
};

2. 修改Discord命令代码

把execute函数改成async函数,用await等待数据库操作完成,同时用try/catch捕获错误:

var db = require('../../etc/database.js');
module.exports = {
 name: "addvip",
 description: "change guild to vip",
 execute: async function(message) {
  const msgID = message.author.id;
  if (!admins.includes(msgID)) return;

  try {
    // 等待checkGuild的异步结果
    const guildExists = await db.checkGuild(message.guild.id);
    
    if (guildExists) {
      const isVip = await db.checkVip('guild', message.guild.id);
      if (isVip) {
        console.log('already vip!');
      } else {
        await db.addVip('guild', message.guild.id);
        console.log('Guild is now vip!');
      }
    } else {
      // 注意:message.guild.owner是用户对象,应该取id存入数据库
      await db.addGuild(message.guild.id, message.guild.name, message.guild.owner.id);
      await db.addVip('guild', message.guild.id);
      console.log('added to vip!');
    }
  } catch (err) {
    // 捕获数据库操作中的错误,避免机器人崩溃
    console.error('Database operation failed:', err);
    console.log('error in addvip');
  }
 }
};

为什么这样能解决问题?
  • Promise可以把异步操作转换成"可以等待"的对象,让我们用同步的写法处理异步逻辑。
  • await会暂停函数执行,直到Promise返回结果,这样就能拿到数据库操作的真实返回值(true/false),而不是undefined。
  • 统一用参数占位符替换字符串拼接,彻底避免SQL注入风险,同时让代码更安全规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:22:33