同步多个数据库的事务逻辑并非易事,而是可行的。解决方案基本上都是关于正确使用承诺,仅此而已......
我们使我们的多数据库事务通过外部承诺公开其最终内部状态,因此我们可以将事务结果与该状态交叉对齐:
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 将抛出,因此第二个不会执行,这很重要,因为在失败的情况下,tx1 或tx2 可能仍然是undefined。这就是为什么我们最后有两个独立的await-s。