如何在同一Express路由中对同一张表执行两个查询并在同一EJS文件中使用返回值?
在Express路由中并行执行多个SQL查询并传递数据到EJS视图
我明白你的问题啦——你现在的代码里两次调用了res.render(),这肯定会出问题,因为一个HTTP请求只能发送一次响应。而且两个异步查询的执行顺序是不确定的,很可能第二个查询还没完成,第一个就已经把响应发出去了。用Promise来处理异步操作确实是正确的思路,我来帮你重构代码:
首先,我们需要把基于回调的db.query转换成Promise形式,这样就能用更清晰的方式处理多个异步操作。然后我们可以并行执行两个查询,等所有结果都返回后,再一次性把所有数据传递给home.ejs。
方案一:使用Promise.all + 链式调用
// 先封装一个Promise版本的查询函数 const queryPromise = (sql) => { return new Promise((resolve, reject) => { db.query(sql, (err, result) => { if (err) reject(err); else resolve(result); }); }); }; app.get('/', (req, res) => { // 定义两个查询的SQL语句(注意修正了你原SQL的语法错误) const countTotalSql = 'SELECT COUNT(*) AS count, FORMAT(SUM(donation_amount),2) AS total FROM donations;'; const latestDonatorSql = 'SELECT CONCAT(first_name, ", ", last_name) AS latest_donator, donation_amount AS amount FROM donations ORDER BY donation_time DESC LIMIT 1;'; // 并行执行两个查询 Promise.all([queryPromise(countTotalSql), queryPromise(latestDonatorSql)]) .then(([countResult, donatorResult]) => { // 提取两个查询的结果 const { count, total } = countResult[0]; const { latest_donator: donatorName, amount } = donatorResult[0] || {}; // 处理没有捐赠记录的情况 // 一次性传递所有数据到视图 res.render('home', { count, total, donatorName, amount }); }) .catch((err) => { console.error('查询出错:', err); res.status(500).send('服务器内部错误'); }); });
方案二:使用async/await(更简洁易读)
如果你用Node.js 8+,async/await会让代码更直观:
// 同样先封装Promise版本的查询函数 const queryPromise = (sql) => { return new Promise((resolve, reject) => { db.query(sql, (err, result) => { if (err) reject(err); else resolve(result); }); }); }; app.get('/', async (req, res) => { try { const countTotalSql = 'SELECT COUNT(*) AS count, FORMAT(SUM(donation_amount),2) AS total FROM donations;'; const latestDonatorSql = 'SELECT CONCAT(first_name, ", ", last_name) AS latest_donator, donation_amount AS amount FROM donations ORDER BY donation_time DESC LIMIT 1;'; // 并行执行两个查询(用Promise.all同时发起,比串行更快) const [countResult, donatorResult] = await Promise.all([ queryPromise(countTotalSql), queryPromise(latestDonatorSql) ]); const { count, total } = countResult[0]; // 处理可能没有捐赠记录的情况,避免报错 const { latest_donator: donatorName, amount } = donatorResult[0] || { latest_donator: '暂无捐赠者', amount: 0 }; res.render('home', { count, total, donatorName, amount }); } catch (err) { console.error('查询失败:', err); res.status(500).send('服务器出错了'); } });
几个关键注意点:
- 修正了SQL语法错误:你原来的第二个SQL里
CONCAT的括号和AS的位置不对,我已经调整过来,还加了DESC确保拿到的是最新的捐赠记录。 - 只调用一次
res.render:所有数据准备好后再统一渲染视图,避免重复响应的错误。 - 错误处理:用
catch或者try/catch捕获错误,避免直接throw err导致服务器崩溃,同时给用户返回合适的错误响应。 - 并行执行查询:用
Promise.all同时发起两个查询,比串行执行效率更高,因为两个查询可以同时在数据库端处理。
内容的提问来源于stack exchange,提问作者Tarik
相关产品推荐
相关产品推荐

