Как заставить 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%2Fdbmgen10%2Fmg -mg-about-s-5060632a.html), доступно в версии 10 и выше. Либо в мастере создания модели синхронизации, либо на странице сопоставлений после создания модели вы можете выбрать, хотите ли вы обнаруживать конфликты на основе строк или столбцов, а также различные типы разрешения конфликтов. То, что вы хотите, соответствует опции разрешения конфликта "метка времени", где вы выбираете существующий столбец метки времени.
К вашему сведению, мастер объясняет параметры больше, чем страница Mappings, поэтому я рекомендую сначала изучить эти параметры в мастере. Обратите внимание, что если параметр "Новые выигрыши с использованием сохраняемого вами столбца метки времени" недоступен, это означает, что в синхронизированных таблицах нет столбца метки времени.
Создав модель, вы можете просмотреть созданные сценарии на странице "События". Когда вы закончите настройку модели, вы развернете ее для создания SQL и пакетных файлов и / или применения SQL непосредственно к базам данных.