5

假设在“db1”中有一个名为“t1”的表,在“db2”中有一个名为“t2”的表,我需要在两个表上插入一条记录,否则失败。

连接到 db1 我想我应该输入这个

BEGIN;
PREPARE TRANSACTION 'pepe'; -- this says the manual that makes your transaction gets stored on disk, so what is the purpose if i can't use it from another database?)

insert into t1 (field) values ('a_value');

COMMIT PREPARED 'pepe'

连接到 db2 我猜

BEGIN;
PREPARE TRANSACTION 'pepe'; -- this fails (the name of the transacttion, what is the meaning, what is use for?)
 -- It complains about this "ERROR:  transaction identifier "pepe" is already in use"

insert into t2 (field) values ('another_value');

COMMIT PREPARED 'pepe'

如您所见,我不知道如何在 postgres 上使用两阶段提交。

TL;博士

我不知道如何在同一个 RDBMS 中的不同数据库上执行同步命令。

在 postgres 官方文档中阅读过,为了在两个或多个不相关的 postgres 数据库中同步工作,我们可以使用所谓的“两阶段提交”协议的实现。

所以我开始尝试看看人们是如何在 postgres 中实际使用它们的,我没有看到任何实际的例子,最多我得到这篇文章,他试图用几个连接到不同数据库的 postgres 客户端进行试验模拟在 pararell 中运行的多个进程对应该以感激(所有提交)或可怕方式(所有回滚)结束的几个 dbs 做事。

我偷看的其他来源是:

请我真的很困惑,我希望 horse_with_no_name 出现在这里并启发我(就像过去发生的那样)或任何其他可以帮助我的慈善灵魂。

提前致谢!

分辨率(在 Laurenz 的回答之后)

连接到 db1,这些是要执行的 sql 行:

BEGIN;
-- DO THINGS TO BE DONE IN A ALL OR NOTHING FASHION
-- Stop point --    
PREPARE TRANSACTION 't1';
COMMIT PREPARED 't1' || ROLLBACK PREPARED 't1' (decision requires awareness and coordination)

同时连接到 db2 这些将是要执行的脚本:

BEGIN;
-- DO THINGS TO BE DONE IN A ALL OR NOTHING FASHION
-- Stop point --  
PREPARE TRANSACTION 't2';

COMMIT PREPARED 't2' || ROLLBACK PREPARED 't2'
  • -- Stop point --是协调进程(例如执行语句的应用程序,或 psql 客户端控制台或 pgAdminII 后面的人)应停止执行两个脚本的地方(实际上不执行任何进一步的指令,这就是我所说的停止)。

  • 然后,首先在 db1 上(然后在 db2 上,反之亦然)必须PREPARE TRANSACTION在每个连接上运行协调进程(无论是否为人)。

    • 如果其中一个失败,那么协调器必须 ROLLBACK PREPARED 在已经准备好事务的那些数据库和其他数据库上 运行ROLLBACK
    • 如果没有人失败,则协调器必须在所有相关数据库上运行 COMMIT PREPARED,这是一项永远不会失败的操作(例如,当您在房子外面一步,所有东西都正确设置为安全退出时,就已经存在了家)
4

1 回答 1

9

我想你误会了PREPARE TRANSACTION

该语句结束事务上的工作,也就是说,它应该在所有工作完成后发出。这个想法是PREPARE TRANSACTION做除了提交本身之外的所有可能在提交期间可能失败的事情。那是为了保证后续COMMIT PREPARED不会失败。

这个想法是处理如下:

  • START TRANSACTION在分布式事务中涉及的所有数据库上运行。

  • 做所有的工作。如果有错误,ROLLBACK所有事务。

  • PREPARE TRANSACTION在所有数据库上运行。如果在任何地方都失败了,ROLLBACK PREPARED请在那些已经准备好事务的数据库和其他数据库上运行ROLLBACK

  • 一旦PREPARE TRANSACTION到处都成功了,COMMIT PREPARED就在所有涉及的数据库上运行。

这样,您可以保证跨多个数据库的“全有或全无”。

这里我没有提到的一个重要组件是分布式事务管理器。它是一个持续记忆上述算法处理当前位置的软件,以便它可以在崩溃后清理或继续提交。

如果没有分布式事务管理器,两阶段提交的价值并不高,而且实际上很危险:如果事务卡在“准备”阶段但尚未提交,它们将继续持有锁并且(在PostgreSQL)即使在服务器重启时也会阻止自动清理工作,因为这样的事务必须是持久的。

这很难做对。

于 2019-11-26T19:33:49.810 回答