Демо IV. Определение и устранение конфликтов
Наш способ разрешения конфликтов будет касаться времени. Конфликты возникают в окружениях ленивой синхронизации. Скорее всего, пользователи ваших приложений не захотят иметь дело с конфликтами. Поэтому вам следует построить ваше приложение таким образом, чтобы конфликты возникали как можно реже. Однако, ваше приложение будет неполным без механизмов разрешения конфликтов. Прежде чем пойти дальше, я дам определение конфликту:
«Будем считать, что строка находится в конфликте, если она изменена в двух или более узлах между запросами синхронизации».
В среде с двумя узлами клиент сможет внести изменения в строку R, находясь в оффлайне, в то же время на сервере могут тоже внести изменения в R. При синхронизации обоих изменений возникает конфликт. В n-узловой среде конфликт может возникнуть из-за независимых изменений, вносимых в R двумя или более клиентами.

Типы конфликтов
Система синхронизации определяет четыре типа конфликтов:
- ClientInsertServerInsert также известен как PK-конфликт; возникает, когда клиент и сервер вставляют строку с одним и тем же PK
- ClientUpdateServerUpdate – наиболее распространенный конфликт, возникающий когда сервер и клиент одновременно изменяют одну и ту же строку
- ClientUpdateServerDelete возникает, когда клиент обновляет некоторую строку, а сервер ее удаляет
- ClientDeleteServerUpdate возникает, когда клиент удаляет некоторую строку, а сервер ее обновляет
Примечание: Использование термина «сервер» в описанных выше типах конфликтов не обязательно означает, что изменения были произведены на сервере. На самом деле сервер может быть всего лишь пассивным узлом, который только собирает и распределяет изменения. Однако, с точки зрения синхронизации клиента, все изменения происходят на сервере.
Чтобы создать каждый из приведенных типов конфликтов, я добавил четыре кнопки в основную форму, как показано на рисунке:
Обнаружение и разрешение конфликтов:

Система синхронизации инициирует ApplyChangeFailedEvent со стороны клиента и сервера, в случае обнаружения конфликта. В этом демонстрационном приложении я зарегистрировал получение событий конфликтов как с сервера так и от клиента. Каждый конфликт представлен пользователю со всеми возможностями его разрешения:
- Игнорировать конфликт и продолжать
- Попробовать еще раз применить изменения. Без изменений данных это приведет к повторному возникновению конфликта. Однако, наша программа не позволяет вам редактировать данные.
- Попробовать еще раз с форсированием записи встроена в ClientSyncProvider на серверной стороне. Вам остается реализовать ее на клиенте, как в нашей программе, где реализован пример разрешения конфликта типа обновление-обновление.
- Прекратить синхронизацию вызвав исключение. Все изменения будут стерты и пересинхронизированы в следующем сеансе.
create procedure dbo.sp_orders_applyupdate ( @sync_last_received_anchor binary(8) , @sync_client_id_hash int , @sync_force_write int, @sync_rowcount int out, @order_id int, @order_date datetime = NULL ) as update [orders] set [order_date] = @order_date, [update_originator_id] = @sync_client_id_hash where (update_timestamp <= @sync_last_received_anchor or update_originator_id = @sync_client_id_hash) and [order_id] = @order_id set @sync_rowcount = @@rowcount
-- force write resolution option if @sync_rowcount = 0 and @sync_force_write = 1 begin update [orders] set [order_date] = @order_date, [update_originator_id] = @sync_client_id_hash set @sync_rowcount = @@rowcount end go
Команды конфликтов SyncAdapter
Существует две команды, с которыми мы не столкнулись в предыдущих демонстрациях:
- SelectConflictUpdatedRowsCommand эта команда находит конфликтующие строки в основной таблице. Во время выполнения программы эта команда запускается в случае неудачного выполнения вставки, обновления или удаления (т.е. возвращения ими 0 количества строк)
- SelectConflictDeletedRowsCommand эта команда находит конфликтующие строки в таблице индексов. Во время выполнения программы эта команда запускается в случае, если конфликтующие строки не найдены в основной таблице. Таким образом определяется конфликт ClientUpdateServerDelete.
Написать эти команды можно очень просто, как показано ниже:
create procedure dbo.sp_orders_getupdateconflict @order_id int as -- this command finds the conflicting row in the base table for [orders] select order_id, order_date from orders where order_id = @order_id go
create procedure dbo.sp_orders_getdeleteconflict @order_id int as -- this command finds the conflicting row in the tombstone table for [orders] select order_id from orders_tombstone where order_id = @order_id go
Шаги инсталляции приложения OfflineAppDemo:
- Запустите SQL Server и загрузите файл demo.sql
- Запустите скрипт до маркера "test sample"
- Загрузите файл server_procs.sql и запустите его для создания процедур синхронизации на сервере
- Загрузите решение VS (OfflineAppDemo-Builder Project)
- Скомпилируйте проект
- Все готово
|