【问题标题】:Why should we use batch() instead of Promise.all?为什么我们应该使用 batch() 而不是 Promise.all?
【发布时间】:2020-09-27 04:04:57
【问题描述】:

来自 pg-promise 常见问题解答Why use method batch instead of promise.all?

在释放连接之前解决在您的任务或事务中创建的所有承诺查询是典型的

我不明白为什么这会是个问题。

对于示例,当我们有一个这样的查询数组时:

  [
    t.any("SELECT pg_sleep(2) as a"),
    t.any('this will fail'),
    t.any("SELECT pg_sleep(3) as b")
  ]

注意:pg_sleep 仅用于测试。
在生产中,这将是 Insert/Update/Delete 语句。而且我们只想在所有事务都成功后提交事务:即当其中任何一个失败时返回错误。

当我们使用 batch() 时:

  • 第一个承诺将在 2 秒后解决
  • 第二个承诺将拒绝
  • 第三个查询仍将发送到数据库并在 3 秒后返回
  • 终于(总共 5 秒后)batch 完成,我们可以向调用者返回错误。

当我们使用 Promise.all() 时:

  • 第一个承诺将在 2 秒后解决
  • 第二个承诺将拒绝 - 这将回滚事务并释放数据库连接
  • 现在我们已经可以向调用者返回错误了
  • 第三个请求将立即失败并返回Querying against a released or lost connection.。这无论如何都是意料之中的,所以我们可以忽略它。

所以我会说Promise.all 更好,因为:

  • 第一个错误后立即返回
  • 甚至不会将第三个无用查询发送到数据库

我错过了什么?
这是否可能会导致其他问题:例如将断开的连接返回到池等。

【问题讨论】:

    标签: pg-promise


    【解决方案1】:

    batch 方法适用于可能创建动态数量的查询的场景。

    它确保所有查询都已解决(已解决或被拒绝),因此您最终不会针对关闭的连接执行查询,并得到 Querying against a released or lost connection 错误。开始让这些错误发生在上下文之外可能会很糟糕/令人困惑,并且您无法诊断正在发生的事情。

    方法Promise.all 不会解决promise,它会在数组中的第一个promise 拒绝时停止处理并拒绝。

    虽然batch 方法仍然非常有用,因为它在处理值方面更灵活,并且比Promise.all 提供更好的结果/错误详细信息,但现在不再需要使用它。它是在 ES5 时代开发的,当时async/await 不存在。但是今天你可以很容易地用async/await替换它:

    旧式:

    db.task('get-all-records', t => {
        return t.batch([
            t.any('SELECT * FROM apples'),
            t.any('SELECT * FROM oranges')
        ]);
    })
        .then([apples, oranges] => {
            // process data here
        })
        .catch(error => {});
    

    新风格:

    const {apples, oranges} = await db.task('get-all-records', async t => {
        const apples = await t.any('SELECT * FROM apples');
        const oranges = await t.any('SELECT * FROM oranges');
        return {apples, oranges};
    });
    

    上面两个例子的结果是相同的,虽然它们在执行逻辑上不一样,因为第一个是完全异步的,而后者使用async/await,这是阻塞操作,它们防止如果之前的查询失败,您甚至可以创建下一个查询。

    附加功能

    在执行多个独立查询(不相互依赖)时,性能最佳的方法是将所有查询连接起来,并将它们作为一个查询执行。

    为此,有方法helpers.concat,加上数据库方法multi,来处理多个结果:

    const queries = [
        {query: 'SELECT * FROM apples WHERE color = $1', values: ['green']},
        'SELECT * FROM oranges'
    ];
    const sql = pgp.helpers.concat(queries);
    
    const [apples, oranges] = await db.multi(sql);
    

    除非您的某些独立查询更改了数据,否则您甚至不需要交易。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-10
      • 2016-05-23
      • 2017-07-09
      • 1970-01-01
      • 2011-01-25
      • 2011-01-07
      • 2017-07-16
      • 1970-01-01
      相关资源
      最近更新 更多