SQL语句在Workbench正常运行,NodeJS调用时触发ER_PARSE_ERROR
问题:多语句SQL执行报错(ER_PARSE_ERROR)
我的代码
let sql = `INSERT INTO Users (Username, Password, FirstName, LastName, Permissions) VALUES ('${req.body.username}', '${hashedPassword}','${req.body.FirstName}','${req.body.LastName}', 'basic_client'); SELECT * FROM Users WHERE UserID = 1523595;`;
报错信息
code: 'ER_PARSE_ERROR', errno: 1064, sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT * FROM Users WHERE UserID = 1523595' at line 1"
已尝试的操作
- 使用多行字符串,发现最后一行的SELECT语句引发问题,单独执行INSERT语句可正常运行;
- 打印输出SQL语句并在Workbench中执行,可正常运行;
- 单独执行查询UserID=1523595的语句在Workbench中也正常;
- 将SQL替换为仅
SELECT 1523595时,服务器可正常执行,但其他语句均不行。
解决方法
问题核心是Node.js的MySQL驱动默认禁止执行多语句查询,这是安全默认配置(防止SQL注入),所以直接拼接INSERT+SELECT的多语句会触发语法错误。
方案1:拆分语句分两次执行(推荐)
把INSERT和SELECT拆成两个独立查询,先执行插入再执行查询:
// 回调写法 connection.query(`INSERT INTO Users (Username, Password, FirstName, LastName, Permissions) VALUES ('${req.body.username}', '${hashedPassword}','${req.body.FirstName}','${req.body.LastName}', 'basic_client')`, (err, insertRes) => { if (err) throw err; connection.query(`SELECT * FROM Users WHERE UserID = 1523595`, (err, selectRes) => { if (err) throw err; console.log(selectRes); // 处理返回结果 }); }); // Async/Await写法(更清晰) async function createAndGetUser() { try { await connection.query(`INSERT INTO Users (Username, Password, FirstName, LastName, Permissions) VALUES ('${req.body.username}', '${hashedPassword}','${req.body.FirstName}','${req.body.LastName}', 'basic_client')`); const user = await connection.query(`SELECT * FROM Users WHERE UserID = 1523595`); console.log(user); } catch (err) { console.error(err); } }
方案2:开启多语句支持(不推荐)
如果必须用多语句,需在创建数据库连接时开启multipleStatements配置,但会大幅提升SQL注入风险,仅建议测试环境临时使用:
const connection = mysql.createConnection({ host: 'localhost', user: 'your_user', password: 'your_password', database: 'your_db', multipleStatements: true // 开启多语句支持 });
方案3:使用INSERT...RETURNING(MySQL 8.0.19+支持)
如果你的MySQL版本符合要求,可直接用RETURNING子句在插入后返回数据,无需单独执行SELECT:
let sql = `INSERT INTO Users (Username, Password, FirstName, LastName, Permissions) VALUES ('${req.body.username}', '${hashedPassword}','${req.body.FirstName}','${req.body.LastName}', 'basic_client') RETURNING *;`;
SQL注入防护建议
针对你提到的后续要处理SQL注入,给出核心建议:
- 强制使用参数化查询:永远不要直接拼接用户输入到SQL语句,用驱动提供的参数占位符:
const sql = `INSERT INTO Users (Username, Password, FirstName, LastName, Permissions) VALUES (?, ?, ?, ?, ?)`; connection.query(sql, [req.body.username, hashedPassword, req.body.FirstName, req.body.LastName, 'basic_client'], (err, results) => { // 处理结果 }); - 禁止开启多语句支持:除非极端场景,否则不要打开
multipleStatements,这是SQL注入高危点; - 校验用户输入:提前过滤非法字符、限制输入长度,比如用户名只允许字母数字下划线;
- 使用ORM框架:如Sequelize、TypeORM,框架会自动处理参数化查询,大幅降低注入风险。
内容的提问来源于stack exchange,提问作者Mel Habip
相关产品推荐
相关产品推荐

