express+MySQL异步执行多条查询语句

并行处理

在写后端接口时,有个需求,需要返回一年四个季度每个季度24小时的统计数据,但是数据库中没有季度这个字段,也没有小时的字段,只有一个时间,时间是完整的,年月日,小时都有,所以可以从时间这个字段中取出季度和小时,但是得执行四个查询语句,如下

const sqls = [
    "select substr(sgfssj, 12, 2) as xs, sum(swrs) as swrs from accident  where sgfssj >= ? and sgfssj < ? and substr(sgfssj, 6, 2) in ('01', '02', '03') group by substr(sgfssj, 12, 2) order by substr(sgfssj, 12, 2) asc",
    "select substr(sgfssj, 12, 2) as xs, sum(swrs) as swrs from accident  where sgfssj >= ? and sgfssj < ? and substr(sgfssj, 6, 2) in ('04', '05', '06') group by substr(sgfssj, 12, 2) order by substr(sgfssj, 12, 2) asc",
    "select substr(sgfssj, 12, 2) as xs, sum(swrs) as swrs from accident  where sgfssj >= ? and sgfssj < ? and substr(sgfssj, 6, 2) in ('07', '08', '09') group by substr(sgfssj, 12, 2) order by substr(sgfssj, 12, 2) asc",
    "select substr(sgfssj, 12, 2) as xs, sum(swrs) as swrs from accident  where sgfssj >= ? and sgfssj < ? and substr(sgfssj, 6, 2) in ('10', '11', '12') group by substr(sgfssj, 12, 2) order by substr(sgfssj, 12, 2) asc",
  ];

上面的查询语句还是比较复杂的,但逻辑比较清楚,就是从时间中取出月份和小时,月份作为筛选条件,时间作为聚合依据和排序值

要执行4条sql语句,但是express中数据库查询是异步的,也就是说,没法通过分段把数据push到最终要的结果中,如果简单push,那么这个结果中永远都是空值。

比如下面的写法:

const data = []
for(let i = 0; i < sqls.length; i++){
    db.query(sqls[i], [s1, s2], (err, results) => {
        data.push(results)
    })
}

上面是个示意

这么写得到的data永远是空数组,原因就是db.query()是异步函数,执行push的时候,results根本就还没有得到

网上搜了一下解决方案,有的说用定时器,有的说用async和await,都比较麻烦,记录一下我最后的处理方案

const data = {};
  async.parallel(
    [
      (parallel_done) => {
        db.query(sqls[0], [startTime, endTime], (err, results) => {
          if (err) return parallel_done(err);
          data.first = results;
          parallel_done();
        });
      },
      (parallel_done) => {
        db.query(sqls[1], [startTime, endTime], (err, results) => {
          if (err) return parallel_done(err);
          data.second = results;
          parallel_done();
        });
      },
    ],
    (err) => {
      if (err) console.log(err)
      db.end();
      res.json(data)
    }
  );

上面的代码也不是完整的,err前应该还有两个parallel_done

简单解释一下,async.parallel是一种并行方式,适用于处理每一个进程,进程之间没有依赖关系,中途某个流程出错就会退出。

2023年7月12日更新

异步处理

随着对node异步编程理解的加深,尝试了一下异步的解决方案,看起来更容易让人接受,记录一下
直接上代码

exports.test = (req, res) => {
	const execute1 = () => {
		return new promise(resolve => {
			db.query(sql[0],[startTime, endTime], (err, results) => {
				if (err) return res.send({ status: 400, message: err });
        		resolve(results);
			})
		})
	}

	const execute2 = () => {
		return new promise(resolve => {
			db.query(sql[1],[startTime, endTime], (err, results) => {
				if (err) return res.send({ status: 400, message: err });
        		resolve(results);
			})
		})
	}

	async function getData(){
		const res1 = await execute1()
		const res2 = await execute2()
		const data = [res1, res2]
		res.send({data})
	}

	getData()
}

以上代码是在csdn的富文本编辑器中纯手写的,没有编译测试,可能会有些bug,可参考这篇博客

Logo

Authing 是一款以开发者为中心的全场景身份云产品,集成了所有主流身份认证协议,为企业和开发者提供完善安全的用户认证和访问管理服务

更多推荐