MySQL命令行可执行的SQL在Node.js应用中执行失败
问题现象
在MySQL命令行以root身份执行以下SQL完全正常:
DROP DATABASE IF EXISTS bugtracker; CREATE DATABASE bugtracker; USE bugtracker;
但通过Node.js代码执行时,抛出语法错误:
Error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE DATABASE bugtracker; USE bugtracker' at line 1
errno: 1064,
sql: 'DROP DATABASE IF EXISTS bugtracker; CREATE DATABASE bugtracker; USE bugtracker;',
sqlState: '42000',
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE DATABASE bugtracker; USE bugtracker' at line 1"
用户涉及的Node.js代码如下:
mysql_funcs.js
import mysql from "mysql2/promise"; export function CreatePool() { return new Promise(function(resolve, reject) { try { let pool = mysql.createPool({ host: '127.0.0.1', user:'appUser', password: 'Password123' }); resolve(pool); } catch(err) { reject(err); } }); } export function GetDBSQL(sql, pool) { return new Promise(function(resolve, reject) { try { let ret = pool.query(sql) resolve(ret); } catch(err) { reject(err); } }); }
main.js
import * as mysqlf from "../common/db/mysql_funcs.js" mysqlf.CreatePool().then( (pool) => { const sqll="DROP DATABASE IF EXISTS bugtracker; CREATE DATABASE bugtracker; USE bugtracker;"; mysqlf.GetDBSQL(sqll, pool).then( (ans) => { console.log("DONE OK"); }, (err) => { console.log(err); } ) });
原因
mysql2/promise驱动默认禁止执行多语句SQL,这是出于安全考虑(防止SQL注入)。而MySQL命令行默认支持多语句执行,所以会出现命令行正常、Node.js报错的差异。
修复方案
方案1:启用多语句支持(需注意安全风险)
在创建连接池时添加multipleStatements: true配置,开启多语句执行权限:
修改CreatePool函数中的配置项:
let pool = mysql.createPool({ host: '127.0.0.1', user:'appUser', password: 'Password123', multipleStatements: true // 新增此行 });
⚠️ 注意:启用该选项后,必须确保所有传入的SQL都是完全可信的,绝对不能将用户输入直接拼接进SQL语句,否则会大幅提升SQL注入风险。
方案2:拆分SQL单独执行(更安全)
不启用多语句,将每个SQL命令分开执行,通过async/await保证执行顺序:
修改main.js代码:
import * as mysqlf from "../common/db/mysql_funcs.js" mysqlf.CreatePool().then(async (pool) => { try { await mysqlf.GetDBSQL("DROP DATABASE IF EXISTS bugtracker;", pool); await mysqlf.GetDBSQL("CREATE DATABASE bugtracker;", pool); await mysqlf.GetDBSQL("USE bugtracker;", pool); console.log("DONE OK"); } catch (err) { console.log(err); } });
另外,也可以在创建连接池时直接指定目标数据库,省去USE语句的执行:
// 创建数据库后,重新初始化连接池时添加database配置 let pool = mysql.createPool({ host: '127.0.0.1', user:'appUser', password: 'Password123', database: 'bugtracker' });
这种方式更安全,避免了多语句带来的注入风险,是推荐的做法。
内容的提问来源于stack exchange,提问作者Sylv99

