NodeJS+Express中MySQL语法错误无法被try-catch捕获如何解决
问题原因
- 你用的
con.query是典型的异步回调API,try/catch只能捕获当前同步执行栈内抛出的错误,无法捕获异步回调中抛出的错误。 - 路由里调用
userDao.findAll()时,con.query会把回调交给事件循环等待SQL执行完成,当前同步代码会直接往下走,执行完后续逻辑后就退出了外层的try/catch上下文。等SQL报错触发回调执行throw err时,外层的try/catch早就执行完毕出栈了,根本接不到这个抛出的错误,最终错误会作为未捕获异常直接打印堆栈,不会进入你写的catch块。 - 额外说明:你当前写的
var result = userDao.findAll()拿到的永远是undefined,因为findAll没有同步返回查询结果,查询结果只存在于异步回调里。
解决方法
你可以选以下任意一种符合你编码习惯的方案修改:
方案1:回调传值(适配传统Node.js回调风格)
不要在DAO层的回调里直接throw错误,而是通过自定义回调函数把错误、结果逐层向外传递:
- 修改DAO层
findAll方法,增加回调参数:
function findAll(callback) { con.query("SELECTTTTTT * FROM user WHERE name = ?", ["Anna"], function (err, result) { if (err) return callback(err, null); callback(null, result); }); }
- 修改路由层逻辑,在回调里处理错误和结果:
router.get('/', function(req, res) { userDao.findAll(function(err, result) { if (err) { console.log("捕获到MySQL语法错误,触发预期日志打印"); return res.status(500).send('服务查询异常'); } res.send('Users home page'); }); });
方案2:Promise + async/await(当前主流写法,支持原生try/catch捕获)
把异步操作包装成Promise,路由用async函数写法,就可以用你原来写的try/catch逻辑捕获错误:
- 修改DAO层
findAll,返回Promise对象:
function findAll() { return new Promise((resolve, reject) => { con.query("SELECTTTTTT * FROM user WHERE name = ?", ["Anna"], function (err, result) { if (err) return reject(err); resolve(result); }); }); }
- 修改路由为async函数,用await等待查询结果:
router.get('/', async function(req, res) { try { var result = await userDao.findAll(); res.send('Users home page'); } catch (err) { console.log("I EXPECTED THIS TEXT TO SHOW UP WHEN FORCING A MYSQL SINTAX ERROR"); res.status(500).send('服务查询异常'); } });
提示:如果使用
mysql2这类升级版MySQL客户端,可以直接引入它的Promise版本,不需要手动包装query方法,写法会更简洁。
内容的提问来源于stack exchange,提问作者tirenweb
相关产品推荐
相关产品推荐

