PG-Promise - 两个数据库的事务逻辑

PG-Promise - transaction logic for two databases

如何使用 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;
}

同步多个数据库的事务逻辑并非微不足道,但可行。解决方案基本上都是关于正确使用 promises,除此之外别无其他...

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

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 只能发生在两个交易或 none.


但是请注意,上面的解决方案相对于事务的状态有点松散,即在我们在那里调用 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。