Как заставить Mobilink синхронизировать таблицы, чтобы последняя обновленная таблица не перезаписывалась?

Вот сценарий. У меня есть консолидированная база данных Oracle. Я использую Mobilink для синхронизации Oracle с базой данных SqlAnywere, которая используется на контроллере. Если пользователь А изменяет запись в удаленной БД на своем портативном устройстве на "сначала обновлен", а затем через 10 минут пользователь Б обновляет ту же запись на своем портативном устройстве на "обновленную секунду", я хочу, чтобы консолидированная база данных всегда показывала "обновленную секунду" после два устройства синхронизированы. В настоящее время, если userB синхронизируется перед userA, в консолидированной базе данных будет указано "сначала обновлено".

2 ответа

Решение

Прямо сейчас вы используете разрешение конфликтов по умолчанию на сервере MobiLink, поэтому по умолчанию последняя синхронизация выигрывает. Вам нужно будет реализовать собственную схему разрешения конфликтов, чтобы справиться с этим.

Это потребует двух вещей, которые должны произойти в удаленной базе данных:

1) В удаленной базе данных должен быть столбец в таблице, который синхронизируется с консолидированной базой данных и отслеживает время обновления записей на удаленном сайте.

2) Вам придется доверять системным часам на удаленных сайтах. Если люди выясняют, как разрешаются конфликты, и хотят, чтобы их данные побеждали в конфликте, ничто не мешает пользователю изменить системное время на своем удаленном устройстве на следующую неделю, обновить свои данные, изменить системное время и затем синхронизация.

В консолидированном, вам нужно реализовать разрешение конфликтов, что не так сложно. Пока ваша таблица не содержит никаких больших двоичных объектов, вы можете записать разрешение конфликта в событие 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

Предполагая, что вы реализовали загрузку на основе меток времени или загрузок моментальных снимков, пульт будет обновлен в соответствии с консолидированным, если консолидированный был обновлен другим пультом с момента последней синхронизации.

Кстати, нужный тип разрешения конфликтов доступен, если вы настроили модель синхронизации ( http://dcx.sybase.com/index.php#http%3A%2F%2Fdcx.sybase.com%2Fhtml%2Fdbmgen10%2Fmg -mg-about-s-5060632a.html), доступно в версии 10 и выше. Либо в мастере создания модели синхронизации, либо на странице сопоставлений после создания модели вы можете выбрать, хотите ли вы обнаруживать конфликты на основе строк или столбцов, а также различные типы разрешения конфликтов. То, что вы хотите, соответствует опции разрешения конфликта "метка времени", где вы выбираете существующий столбец метки времени.

К вашему сведению, мастер объясняет параметры больше, чем страница Mappings, поэтому я рекомендую сначала изучить эти параметры в мастере. Обратите внимание, что если параметр "Новые выигрыши с использованием сохраняемого вами столбца метки времени" недоступен, это означает, что в синхронизированных таблицах нет столбца метки времени.

Создав модель, вы можете просмотреть созданные сценарии на странице "События". Когда вы закончите настройку модели, вы развернете ее для создания SQL и пакетных файлов и / или применения SQL непосредственно к базам данных.

Другие вопросы по тегам