Как заставить Mobilink синхронизировать таблицы, чтобы самая последняя обновленная таблица не была перезаписана?
-
06-09-2019 - |
Вопрос
Вот сценарий.У меня есть консолидированная база данных Oracle.Я использую Mobilink для синхронизации Oracle с базой данных SqlAnywere, которая используется на портативном компьютере.Если пользователь А меняет запись в удаленной базе данных на своем портативном устройстве на «обновлено первой», а затем через 10 минут пользователь Б обновляет ту же запись на своем портативном устройстве на «обновлено вторым», я хочу, чтобы консолидированная база данных всегда показывала «обновлено вторым» после два устройства синхронизированы.В настоящее время, если пользователь B синхронизируется раньше пользователя A, в консолидированной базе данных будет указано «сначала обновлено».
Решение
Прямо сейчас вы используете разрешение конфликтов по умолчанию на сервере 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:
МобиЛинк - Администрирование сервера
Методы синхронизации
Разрешение конфликтов
Другие советы
Предполагая, что вы реализовали загрузку на основе временных меток или загрузку моментальных снимков, тогда удаленный компьютер будет обновлен в соответствии с консолидированными данными, если консолидированные данные были обновлены другим удаленным устройством с момента последней синхронизации.
Кстати, желаемый тип разрешения конфликтов доступен, если вы настроили модель синхронизации (http://dcx.sybase.com/index.php#http%3A%2F%2Fdcx.sybase.com%2Fhtml%2Fdbmgen10%2Fmg-mg-about-s-5060632a.html), доступный в версии 10 и выше.Либо в мастере создания модели синхронизации, либо на странице «Сопоставления» после создания модели вы можете выбрать, хотите ли вы обнаруживать конфликты на основе строк или столбцов, а также различные типы разрешения конфликтов.То, что вам нужно, соответствует опции разрешения конфликта «метка времени», где вы выбираете существующий столбец метки времени.
К вашему сведению, мастер объясняет параметры больше, чем страница «Сопоставления», поэтому я рекомендую сначала изучить эти параметры в мастере.Обратите внимание: если параметр «Побеждает более новый, используя поддерживаемый вами столбец временной метки», это означает, что в синхронизированных таблицах нет столбца временной метки.
После создания модели вы можете просмотреть сгенерированные сценарии на странице «События».Завершив настройку модели, вы развертываете ее для создания SQL и пакетных файлов и/или применяете SQL непосредственно к базам данных.