跨数据库同步表数据

时间:2013-03-05 11:30:24

标签: java sql spring-batch

我有一个表在字段上记录其行插入/更新时间戳。

我想将此表中的数据与另一个数据库服务器上的另一个表同步。两个数据库服务器未连接,同步是单向(主/从)。使用表触发器不合适

我的工作流程:

  • 我使用全局last_sync_date参数和查询表Master 已更改/插入的记录
  • 将结果行输出到xml
  • 使用更新和插入
  • 解析xml并更新表Slave

在处理Master表的已删除记录时,问题的复杂性会增加。为了捕获已删除的记录,我认为我必须为先前插入的记录维护一个日志表并使用sql“NOT IN”。在处理大型数据集时,这会成为性能问题。

处理这种情况的替代工作流程是什么?

10 个答案:

答案 0 :(得分:9)

听起来您需要一个交易消息队列。

这是如何工作的很简单。更新主数据库时,您可以向消息代理(无论更新是什么)发送消息,该代理可以转到任意数量的队列。每个从属数据库都可以拥有自己的队列,并且由于队列保持顺序,进程最终应该正确同步(具有讽刺意味的是,这是大多数RDBMS在内部进行复制的方式)。

将Message Queue视为一种SCM更改列表或补丁列表数据库。在大多数情况下,发送给master的相同(或大致相同)的SQL语句应该是最终复制到其他数据库。不要担心丢失消息,因为大多数消息队列都支持持久性和事务。

我建议您查看和/或,特别是因为您使用标记了此问题。

根据您的意见:

BTW你担心NOT IN是一个性能问题不是很好,因为有太多的解决办法,但考虑到你不想做DB特定的事情(比如触发和复制),我仍然觉得消息队列是您的最佳选择。

编辑 - 非MQ路线

由于我给你一个关于提出这个问题的艰难时期,我将继续努力提供帮助。 除了消息队列,你可以像我们之前尝试的那样做一些XML文件。模式中需要的关键功能是主数据库上的CREATE TIMESTAMP列,以便您可以在系统启动和运行时执行批处理(否则您将不得不停止系统)。现在,如果你走这条路线,你会希望SELECT * WHERE CREATE_TIME < ?小于当前时间。基本上你只能在快照中获取行。

现在,在您的其他数据库中删除您要删除ID表上inner joining的行但!=(即您可以使用JOINS而不是慢NOT IN)。幸运的是,您只需要删除所有ids而不需要其他列。您可以使用基于更新时间戳列的增量的其他列(用于更新,并创建aka插入)。

答案 1 :(得分:5)

答案 2 :(得分:2)

为什么不直接添加指示上次更新/插入/删除时间的TIMESTAMP列?然后添加一个已删除的列 - 即。将该行标记为已删除,而不是立即将其删除。导出删除操作后删除它。

如果您无法更改现有应用中的架构使用情况:

你根本不能使用触发器吗?第二个(“隐藏”)表如何填充每个插入/更新/删除,并构成下一个生成的xml导出文件的内容?这是一个常见的概念:历史(或“日志”)表:它将有自己的进度id列,可用作导出标记。

答案 3 :(得分:2)

查看Oracle GoldenGate

  

Oracle GoldenGate是一个全面的软件包,用于启用   在异构数据环境中复制数据。该产品   set支持高可用性解决方案,实时数据集成,   事务性变更数据捕获,数据复制,转换,   运营和分析企业之间的验证   系统

SymmetricDS

  

SymmetricDS是用于多主数据库的开源软件   复制,过滤同步或跨越的转换   异构环境中的网络。它支持多种   具有单向或双向异步数据的订户   复制。

Daffodil Replicator

  

Daffodil Replicator是一个用于数据同步和数据的Java工具   迁移和各种数据库服务器之间的数据备份。

答案 4 :(得分:1)

非常有趣的问题。

在可能的情况下,我有足够的RAM来加载主表和从表中的所有ID以区分它们。

如果主表中的ID是顺序的,您可以尝试在主表中维护一组完整填充范围(使用所有ID的范围,没有空格,如100,101,102,103)。

要查找已移除的ID而不将其全部加载到内存中,您可以执行SQL查询以计算每个完整填充区域id >= full_region.start and id <= full_region.end的记录数。如果查询== (full_region.end - full_region.end) + 1的结果,则表示区域中的所有记录都已删除。否则 - 将区域分成两部分并对它们进行相同的检查(在很多情况下,只有一侧包含已删除的记录)。

经过一段长度(我认为大约5000)后,加载所有现有ID并使用Set检查是否缺席会更快。

还有一种感觉是将所有ID加载到内存中,用于一批小型(10-20个记录)区域。

答案 5 :(得分:1)

为需要同步的表创建一个历史表(基本上是该表的副本,可能还有一些额外的字段),并在每次在活动表中插入/更新/删除某些内容时插入整行。

编写一个Spring批处理作业,根据历史记录表的额外字段

将数据同步到Slave机器

希望这会有所帮助..

答案 6 :(得分:1)

允许在当前工作流程中删除的潜在选项:

如果触发器限制仅限于跨数据库引用的触发器,则当前工作流程中可能的解决方案是在主数据库中创建一个帮助程序表,以仅存储已删除行的唯一标识符(或任何其他内容)唯一键可以让您最有效地删除已删除的行。)

这些ID需要在删除时由主表上的触发器插入。

使用与插入/更新相同的机制,在插入和更新后创建任务。您可以将助手表导出到xml,如您当前工作流程中所述。

此任务只是从slave表中删除行,然后在完成任务后从helper表中删除所有数据。记录任务中的任何错误,以便您可以对此进行故障排除,因为没有审计跟踪。

答案 7 :(得分:1)

如果您的数据库有一个事务转储日志,请运送该日志。

可以使用MySQL,并且可以使用PostgreSQL。

答案 8 :(得分:0)

我同意另一条评论 - 这需要使用触发器。我认为另一个表应该包含sql语句的历史记录。有关使用2008扩展事件的信息,请参阅this answer ...然后,您可以获取整个sql,并将结果查询存储在历史记录表中。如果您想将其存储为mysql查询或mssql查询,则由您决定。

答案 9 :(得分:0)

这是我的看法。你真的需要处理这件事吗?我假设奴隶是出于报告目的。所以我要问的问题是它应该是最新的吗?如果数据是一天之久可以吗?你计划每晚刷新吗?

如果是这样,忘掉这个在线同步过程,下载完整的表格;将它发送到mysql并批量加载它。处理时间可能比您想象的要快得多。