如何让 Mobilink 同步表,以便不覆盖最近更新的表?

Posted

技术标签:

【中文标题】如何让 Mobilink 同步表,以便不覆盖最近更新的表?【英文标题】:How do you get Mobilink to synchronize tables so that the most recent updated table is not overwritten? 【发布时间】:2009-06-02 20:47:55 【问题描述】:

这里是场景。我有一个 Oracle 统一数据库。我正在使用 Mobilink 将 Oracle 与手持设备上使用的 SqlAnywere 数据库同步。 如果 userA 将其手持设备上的远程 DB 中的记录更改为“首先更新”,然后 10 分钟后 userB 将其手持设备上的同一记录更新为“第二个更新”,我希望统一数据库在之后始终显示“第二个更新”两个设备是同步的。目前,如果 userB 在 userA 之前同步,则统一数据库将读取“首先更新”。

【问题讨论】:

【参考方案1】:

现在,您在 MobiLink 服务器中使用默认的冲突解决方案,因此默认情况下最后一个同步获胜。您需要实施自己的冲突解决方案来处理此问题。

这需要在远程数据库发生两件事:

1) 远程数据库的表中需要有一列与统一数据库同步,用于跟踪远程站点上记录的更新时间。

2) 您必须信任远程站点的系统时钟。如果人们弄清楚冲突是如何解决的并且他们希望确保他们的数据赢得冲突,那么没有什么可以阻止用户将远程设备上的系统时间更改为下周,更新他们的数据,将系统时间更改回然后同步。

在合并时,您需要实施冲突解决,这并不难。只要您的表不包含任何 blob,您就可以在表的 upload_update 事件中编写冲突解决方案。让我们假设远程数据库中的表如下所示:

create table Admin (
  admin_id           bigint default global autoincrement(1000000) primary key,
  data               varchar(64) not null,
  rem_last_modified  timestamp not null default timestamp
);

我们还假设合并中的一个表看起来非常相似,但还有另一个最后修改的列来跟踪合并中行的更改时间。

create table Admin (
  admin_id           bigint default global autoincrement(1000000) primary key,
  data               varchar(64) not null ,
  rem_last_modified  timestamp not null default ‘1900-01-01’,
  cons_last_modified timestamp default timestamp
);

通常,您的 upload_update 事件看起来像这样:

call ml_add_table_script( 'v1', 'Admin', 'upload_update',
'update Admin set data = ml r.data, 
              rem_last_modified = ml r.rem_last_modified  
 where admin_id = ml r.admin_id'
);

相反,我们将重写您的 upload_update 事件以调用存储过程,并从远程数据库中传递旧行值。

call ml_add_table_script( 'v1', 'Admin', 'upload_update',
'call admin_upload_update( ml r.admin_id, 
    ml r.data, ml r.rem_last_modified, 
    ml o.data, ml o.rem_last_modified’
);

您的存储过程的关键是我们要进行更新,但更新的 where 子句将包括主键值和远程数据库中的旧行值。如果有人更改了合并中的行,则此更新将更新零行,并且我们知道发生了冲突。如果它更新一行,则没有冲突。您的存储过程将如下所示(下面的伪 SQL):

create procedure admin_upload_update ( 
    @admin_id bigint, 
    @new_data varchar(64), 
    @new_rem_lmod timestamp,
    @old_data varchar(64), 
    @old_rem_lmod timestamp 
)
begin
    declare @cur_rem_lmod timestamp;
    update admin set data = @new_data, rem_last_modified = @new_rem_lmod
     where admin_id = @admin_id 
       and data = @old_data 
       and rem_last_modified = @old_rem_lmod;
    if @@rowcount = 0 then
        // conflict !!
        select rem_last_modified into @cur_rem_lmod 
          from admin where admin_id = @admin_id;
        if @new_rem_lmod > @cur_rem_lmod then
            // update using new_data and new_rem_lmod
        else 
            // do nothing, current values in cons wins
        end if;
    end if;  
end;

有关解决冲突的更多信息,请参阅 v10 文档的以下部分:

MobiLink - 服务器管理

同步技术

处理冲突

http://dcx.sybase.com/index.php#http%3A%2F%2Fdcx.sybase.com%2Fhtml%2Fdbmlen10%2Fml-conflicts-synch.html

【讨论】:

如果在upload_update 事件中没有更新统一数据库会发生什么?我希望更新远程数据库以匹配合并的数据库。我该怎么做呢?还是这是默认行为?【参考方案2】:

假设您已经实现了基于时间戳的下载或快照下载,那么如果自上次同步以来整合由另一个远程更新,那么远程将被更新以匹配整合。

顺便说一句,如果您设置了同步模型 (http://dcx.sybase.com/index.php#http%3A%2F%2Fdcx.sybase.com%2Fhtml%2Fdbmgen10%2Fmg-mg-about-s-5060632a.html),则可以使用您想要的冲突解决类型,该模型在版本 10 及更高版本中可用。无论是在 Create Synchronization Model 向导中,还是在模型创建后的 Mappings 页面中,您都可以选择是需要基于行还是基于列的冲突检测,以及不同类型的冲突解决。您想要的对应于“时间戳”冲突解决选项,您可以在其中选择现有的时间戳列。

仅供参考,向导解释的选项比映射页面更多,所以我建议先在向导中探索这些选项。请注意,如果“较新者获胜,使用您维护的时间戳列”选项为灰色,则表示同步表中没有时间戳列。

创建模型后,您可以在“事件”页面中预览生成的脚本。完成模型设置后,将其部署以创建 SQL 和批处理文件和/或将 SQL 直接应用于数据库。

【讨论】:

以上是关于如何让 Mobilink 同步表,以便不覆盖最近更新的表?的主要内容,如果未能解决你的问题,请参考以下文章

SQLE_NOT_PUBLIC_ID Sybase mobilink 错误

MobiLink 同步脚本生成

MySQL mobilink 与 SQL Anywhere 同步

外部覆盖后 Spark 和 Hive 表架构不同步

如何在 Chrome 的 JavaScript 中覆盖/扩展 ReferenceError?

navicat中数据传输数据同步结构同步的区别