两端使用相同的数据库系统并使用复制
如果您的远程端也是 PostgreSQL,您可以使用带热备份的流式复制,以透明且自动地保持远程端与本地同步。
如果本地端和远程端都是 MySQL,你可以使用 MySQL 的各种复制功能(如 binlog 复制)做类似的事情。
使用外部脚本同步
使用外部脚本没有任何问题。事实上,即使您使用 DBI-Link 或类似工具(见下文),您也可能必须使用psql
cron 作业中的外部脚本(或 )来启动复制,除非您打算使用PgAgent来执行此操作。
要么在由触发器过程维护的队列表中累积行,要么确保您可以编写始终可靠地仅选择新行的查询。然后连接到目标数据库和INSERT
新行。
如果要复制的行太大而无法舒适地放入内存中,您可以使用游标并使用FETCH读取行,如果要复制的行太大而无法舒适地放入内存中,这将很有帮助。
我会按以下顺序完成工作:
- 连接到 PostgreSQL
- 连接到 MySQL
- 开始一个 PostgreSQL 事务
- 开始一个 MySQL 事务。如果你的 MySQL 正在使用 MyISAM,现在就去修复它。
- 从 PostgreSQL 读取行,可能通过游标或使用
DELETE FROM queue_table RETURNING *
- 将它们插入 MySQL
DELETE
PostgreSQL 中队列表中的任何行(如果您还没有的话)。
COMMIT
MySQL 事务。
- 如果 MySQL
COMMIT
成功,COMMIT
则 PostgreSQL 事务。如果失败,ROLLBACK
则 PostgreSQL 事务并再次尝试整个事情。
PostgreSQLCOMMIT
不太可能失败,因为它是一个本地数据库,但如果您需要完美的可靠性,您可以在 PostgreSQL 端使用两阶段提交,您可以:
PREPARE TRANSACTION
在 PostgreSQL 中
COMMIT
在 MySQL 中
- 然后取决于 MySQL 提交的结果
COMMIT PREPARED
或者在 PostgreSQL 中。ROLLBACK PREPARED
这对于您的需求来说可能太复杂了,但这是完全确定更改发生在两个数据库上的唯一方法,或者两者都不会发生,而不仅仅是一个。
顺便说一句,说真的,如果您的 MySQL 使用MyISAM表存储,您可能应该对此进行补救。它容易在崩溃时丢失数据,并且无法进行事务更新。转换为InnoDB。
在 PostgreSQL 中使用 DBI-Link
也许是因为我对 PostgreSQL 很满意,但我会使用一个使用DBI-link via的 PostgreSQL 函数PL/Perlu
来完成这项工作。
当应该进行复制时,我会运行一个PL/PgSQL
使用PL/Perl
DBI-Link 连接到 MySQL 数据库并将数据插入到队列表中的过程。
DBI-Link 的例子很多,这里不再赘述。这是一个常见的用例。
使用触发器对更改进行排队,并使用 DBI-link 进行同步
如果您只想复制新行并且您的表是仅追加的,您可以编写一个触发器过程,将所有新INSERT
编辑的行追加到一个与主表具有相同定义的单独队列表中。当您想要同步时,您的同步过程可以在单个事务LOCK TABLE the_queue_table IN EXCLUSIVE MODE;
中复制数据,然后DELETE FROM the_queue_table;
。这保证不会丢失任何行,尽管它仅适用于INSERT
-only 表。在目标表上处理UPDATE
和DELETE
是可能的,但要复杂得多。
使用外部数据包装器将 MySQL 添加到 PostgreSQL
或者,对于 PostgreSQL 9.1 及更高版本,我可能会考虑使用MySQL Foreign Data Wrapper、ODBC FDW或JDBC FDW来允许 PostgreSQL 像查看本地表一样查看远程 MySQL 表。然后我可以使用可写的 CTE来复制数据。
WITH moved_rows AS (
DELETE FROM queue_table RETURNING *
)
INSERT INTO mysql_table
SELECT * FROM moved_rows;