Node.js自定义MySQL函数返回undefined问题求助
问题根源:异步操作的返回值处理错误
你的所有数据库操作函数返回undefined,核心原因是**mysql.query是异步操作**——你在回调函数里写的return true/false,只会返回给回调函数本身,而外层的数据库函数(比如checkGuild)在调用mysql.query后会立刻执行完毕,默认返回undefined,根本拿不到回调里的结果。
另外还有两个小问题需要注意:
- 部分函数用字符串拼接SQL语句,存在SQL注入风险(比如
addGuild),应该统一用参数占位符(就像你在checkVip里做的那样)。 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
相关产品推荐
相关产品推荐

