【问题标题】:PG-Promise - transaction logic for two databasesPG-Promise - 两个数据库的事务逻辑
【发布时间】:2021-06-20 12:54:12
【问题描述】:

如何使用 PG-Promise 在两个不同的数据库之间分配事务?提交或回滚应该应用于两个数据库,如果一个失败,另一个应该恢复更改

我一直在使用这样的东西,但我不确定它是否有效:

try {
    await firstDb.tx(async (firstDbTask) => {
      await secondDb.tx(async (secondDbTask) => {
        // second db stuff
      })
      // first db stuff
    });

    return true;
} catch (err) {    
    return err;
}

【问题讨论】:

  • 您在这里将两个不相关的主题混合为一个问题。一个是关于跨数据库的分布式事务,另一个是关于与pg-promise 链接的事务。这两件事是无关的。您需要先更好地了解它在做什么,然后再提出更好的问题。
  • 我想知道多个数据库之间的分布式事务。编辑问题和标题
  • 请注意,在您接受后,我彻底修改了我的答案。最初的答案存在一些问题。现在看起来好多了;)

标签: pg-promise


【解决方案1】:

同步多个数据库的事务逻辑并非易事,而是可行的。解决方案基本上都是关于正确使用承诺,仅此而已......

我们使我们的多数据库事务通过外部承诺公开其最终内部状态,因此我们可以将事务结果与该状态交叉对齐:

let firstTx, secondTx;

firstTx = new Promise((resolve, reject) => {
    firstDb.tx(async t => {
        // do your queries here first...

        // success, signal after all the queries:
        resolve(/*null or whatever data*/);

        // Align COMMIT-ROLLBACK logic with the other transaction:
        await secondTx;
    }).catch(reject);
});

secondTx = new Promise((resolve, reject) => {
    secondDb.tx(async t => {
        // do your queries here first...

        // success, signal at the end:
        resolve(/*null or whatever data*/);

        // Align COMMIT-ROLLBACK logic with the other transaction:
        await firstTx;
    }).catch(reject);
});

await Promise.all([firstTx, secondTx]); // finish transactions logic

这种方法可确保如果其中一个事务失败,两个事务都会回滚。而COMMIT 只能发生在两个事务中,也可能不发生。


但是请注意,上面的解决方案相对于事务的状态有点松散,即在我们在那里调用Promise.all 之后,两个事务都完成了它们的逻辑执行,但是生成的COMMIT / ROLLBACK还没执行完。

如果您需要完全关闭两个交易,您必须单独发送await 以结束实际交易,如下所示:

let firstTx, secondTx, tx1, tx2;

firstTx = new Promise((resolve, reject) => {
    tx1 = firstDb.tx(async t => {
        // do your queries here first...

        // success, signal after all the queries:
        resolve(/*null or whatever data*/);

        // Align COMMIT-ROLLBACK logic with the other transaction:
        await secondTx;
    }).catch(reject);
});

secondTx = new Promise((resolve, reject) => {
    tx2 = secondDb.tx(async t => {
        // do your queries here first...

        // success, signal at the end:
        resolve(/*null or whatever data*/);

        // Align COMMIT-ROLLBACK logic with the other transaction:
        await firstTx;
    }).catch(reject);
});

await Promise.all([firstTx, secondTx]); // finish transactions logic

await Promise.all([tx1, tx2]); // finish transactions execution

// All COMMIT-s or ROLLBACK-s have been executed.

请注意,仅当两个事务都以COMMIT 成功时,上述规定才有意义。当其中一个失败时,第一个await 将抛出,因此第二个不会执行,这很重要,因为在失败的情况下,tx1tx2 可能仍然是undefined。这就是为什么我们最后有两个独立的await-s。

【讨论】:

  • 这太好了,谢谢。我的情况看起来很有希望(呵呵)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
  • 1970-01-01
  • 2010-11-20
  • 2020-09-05
  • 2014-06-07
  • 2011-10-23
  • 1970-01-01
相关资源
最近更新 更多