You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express异步请求处理的并发与数据一致性问题

Express路由并发与数据库一致性问题解答

一、顺序执行数据库调用的场景

对应的路由代码:

app.get('/all', async (req, res) => {
  // foo、bar、baz为数据库调用,因依赖关系顺序执行
  const fooRes = await foo();
  const barRes = await bar(fooRes);
  const bazRes = await baz(barRes);

  res.send({data: [fooRes,barRes,bazRes]})
});

app.post('/foo', async (req, res) => {
  // 更新foo数据
});

app.post('/bar', async (req, res) => {
  // 更新bar数据
});

app.post('/baz', async (req, res) => {
  // 更新baz数据
});

针对问题的解答:

  • 其他用户完全可以调用/foo进行数据更新。Express基于事件循环实现异步处理,当/all路由中的await baz(barRes)暂停当前请求执行时,事件循环会立即处理其他进来的请求(比如/foo的POST请求),不会阻塞整个服务。
  • 会存在返回过时数据的风险。例如:用户A的/all请求已获取fooRes,此时用户B调用/foo更新了foo的数据,但用户A的/all后续流程仍使用旧的fooRes,最终返回的foo数据就是更新前的过时值。如果业务要求/all返回的是同一时间点的一致数据快照,这种顺序异步调用的方式无法保证数据一致性。

二、Promise.all并行执行的场景

对应的/all路由代码:

app.get('/all', async (req, res) => {
  const data = await Promise.all([
    foo(),
    bar(),
    baz()
  ]);

  res.send({ data })
});

// 上述/foo、/bar、/baz更新路由保持不变

针对问题的解答:

  • 不能认为用户1的baz()调用一定先于用户2的/baz更新执行。Express接收请求的顺序是确定的,但从Express将请求转发到数据库的过程中,存在诸多不确定因素:比如用户1的baz()查询因数据库内部队列、网络延迟等原因,实际到达数据库的时间晚于用户2的/baz更新请求;或者数据库本身采用异步调度处理请求,执行顺序由数据库决定,而非Express接收请求的顺序。
  • 完全有可能出现用户1的/all请求返回更新后的baz数据。只要用户2的/baz更新请求先于用户1的baz()查询到达数据库并完成执行,用户1的查询就会读取到更新后的值——哪怕用户1的/all请求更早到达Express。

内容的提问来源于stack exchange,提问作者hangry horse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 18:01:15