Первое, что вам нужно решить, это общая политика относительно того, какая сторона считается «авторитетной» в случае противоречивых изменений.
То есть: предположим, что запись № 125 была изменена на сервере 5 января в 22:00, и такая же запись была изменена на одном из телефонов (назовем ее клиентом A) 5 января в 23:00. Последняя синхронизация была 3 января. Затем пользователь снова подключается, скажем, 8 января.
Определить, что нужно изменить, «легко» в том смысле, что и клиент, и сервер знают дату последней синхронизации, поэтому все, что было создано или обновлено (подробнее об этом см. Ниже) с момента последней синхронизации, должно быть согласовано.
Итак, предположим, что единственная измененная запись - № 125. Вы либо решаете, что одна из двух автоматически «побеждает» и перезаписывает другой, либо вам необходимо поддерживать фазу согласования, когда пользователь может решить, какая версия (серверная или клиентская) является правильной, перезаписывая другую.
Это решение чрезвычайно важно, и вы должны взвесить «роль» клиентов. Особенно, если существует потенциальный конфликт не только между клиентом и сервером, но и в случае, если разные клиенты могут изменять одну и ту же запись (записи).
[Предполагая, что № 125 может быть изменен вторым клиентом (клиентом B), есть вероятность, что клиент B, который еще не синхронизировался, предоставит еще одну версию той же записи, что делает предыдущее разрешение конфликта спорным]
Что касается пункта « создано или обновлено » выше ... как вы можете правильно идентифицировать запись, если она была создана на одном из клиентов (при условии, что это имеет смысл в вашей проблемной области)? Предположим, ваше приложение управляет списком деловых контактов. Если клиент A говорит, что вам нужно добавить недавно созданного Джона Смита, а на сервере есть Джон Смит, созданный вчера клиентом D ... создаете ли вы две записи, потому что не можете быть уверены, что они не разные люди? Вы попросите пользователя уладить и этот конфликт?
Есть ли у клиентов «владение» подмножеством данных? Т.е. если клиент B настроен как «авторитет» для данных для области №5, может ли клиент A изменять / создавать записи для области №5 или нет? (Это упростит разрешение некоторых конфликтов, но может оказаться невыполнимым в вашей ситуации).
Подводя итог, можно выделить следующие основные проблемы:
- Как определить "идентичность", учитывая, что отключенные клиенты могли не получить доступ к серверу до создания новой записи.
- Предыдущая ситуация, независимо от того, насколько сложным является решение, может привести к дублированию данных, поэтому вы должны предвидеть, как периодически решать эти проблемы и как информировать клиентов о том, что то, что они считали «записью № 675», действительно было объединено / заменено Запись # 543
- Решите, будут ли конфликты разрешаться указанием (например, «Версия сервера всегда превосходит версию клиента, если первая была обновлена с момента последней синхронизации») или вручную.
- В случае фиата , особенно если вы решите, что клиент имеет приоритет, вы также должны позаботиться о том, как поступать с другими, еще не синхронизированными клиентами, которые могут иметь еще некоторые изменения.
- В предыдущих пунктах не учитывалась детализация ваших данных (чтобы упростить описание). Достаточно сказать, что вместо рассуждений на уровне «записи», как в моем примере, вы можете найти более подходящим записывать изменения на уровне поля. Или работать с набором записей (например, запись человека + запись адреса + запись контактов), одновременно рассматривая их совокупность как своего рода «мета-запись».
Библиография:
Подробнее об этом, конечно же, в Википедии .
Простой алгоритм синхронизации от автора Vdirsyncer
Статья OBJC о синхронизации данных
SyncML®: синхронизация и управление мобильными данными (Книга в O'Reilly Safari)
Бесконфликтные реплицированные типы данных
Оптимистическая репликация ЯСУШИ САЙТО (HP Laboratories) и МАРК ШАПИРО (Microsoft Research Ltd.) - ACM Computing Surveys, Vol. V, № N, 3, 2005.
Александр Трауд, Юрген Наглер-Ихляйн, Франк Каргл и Майкл Вебер. 2008. Циклическая синхронизация данных посредством повторного использования SyncML. В материалах Девятой Международной конференции по управлению мобильными данными (MDM '08). IEEE Computer Society, Вашингтон, округ Колумбия, США, 165–172. DOI = 10.1109 / MDM.2008.10 http://dx.doi.org/10.1109/MDM.2008.10
Лам Ф., Лам Н. и Вонг Р. 2002. Эффективная синхронизация мобильных XML-данных. В материалах одиннадцатой международной конференции по управлению информацией и знаниями (Маклин, Вирджиния, США, 4–9 ноября 2002 г.). ЦИКМ '02. ACM, Нью-Йорк, Нью-Йорк, 153–160. DOI = http://doi.acm.org/10.1145/584792.584820
Cunha, PR и Maibaum, TS 1981. Resource & equil; абстрактный тип данных + синхронизация - Методология программирования, ориентированного на сообщения -. В материалах 5-й международной конференции по разработке программного обеспечения (Сан-Диего, Калифорния, США, 9–12 марта 1981 г.). Международная конференция по программной инженерии. IEEE Press, Пискатауэй, Нью-Джерси, 263-272.
(Последние три взяты из цифровой библиотеки ACM, не знаю, являетесь ли вы ее участником или можете получить их по другим каналам).
С сайта доктора Доббса :
- Создание приложений с помощью SQL Server CE и SQL RDA, Билл Вагнер, 19 мая 2004 г. (Лучшие практики разработки приложений для настольных и мобильных ПК - Windows / .NET)
С arxiv.org:
- Бесконфликтный реплицированный тип данных JSON - в документе описывается реализация JSON CRDT (бесконфликтные реплицированные типы данных - CRDT - это семейство структур данных, которые поддерживают одновременное изменение и гарантируют конвергенцию таких одновременных обновлений).
Я бы порекомендовал вам поставить отметку времени столбец в каждой таблице и каждый раз, когда вы вставляете или обновляете, обновляйте значение метки времени каждой затронутой строки. Затем вы перебираете все таблицы, проверяя, является ли метка времени более новой, чем та, которая есть в целевой базе данных. Если новее, то проверьте, надо ли вставлять или обновлять.
Наблюдение 1: помните о физическом удалении, поскольку строки удаляются из исходной базы данных, и вы должны сделать то же самое на сервере базы данных. Вы можете решить эту проблему, избегая физического удаления или записывая каждое удаление в таблице с отметками времени. Примерно так:
DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)
Итак, вам нужно прочитать все новые строки таблицы DeletedRows и выполнить удаление на сервере, используя table_name, pk_column и pk_column_value.Наблюдение 2: помните о FK, поскольку вставка данных в таблицу, относящуюся к другой таблице, может не удастся. Вы должны деактивировать каждый FK перед синхронизацией данных.
источник
Если кто-то сталкивается с подобной проблемой дизайна и ему необходимо синхронизировать изменения на нескольких устройствах Android, я рекомендую проверить Google Cloud Messaging для Android (GCM).
Я работаю над одним решением, в котором изменения, сделанные на одном клиенте, должны распространяться на других клиентов. И я только что реализовал доказательство реализации концепции (сервер и клиент), и это работает как шарм.
По сути, каждый клиент отправляет на сервер дельта-изменения. Например, идентификатор ресурса ABCD1234 изменился со 100 на 99.
Сервер проверяет эти дельта-изменения в своей базе данных и либо утверждает изменение (клиент синхронизирован) и обновляет свою базу данных, либо отклоняет изменение (клиент не синхронизирован).
Если изменение одобрено сервером, сервер затем уведомляет других клиентов (за исключением того, кто отправил изменение дельты) через GCM и отправляет многоадресное сообщение, несущее такое же изменение дельты. Клиенты обрабатывают это сообщение и обновляют свою базу данных.
Классно то, что эти изменения распространяются практически мгновенно !!! если эти устройства подключены к сети. И мне не нужно реализовывать какой-либо механизм опроса на этих клиентах.
Имейте в виду, что если устройство слишком долго находится в автономном режиме и в очереди GCM ожидает доставки более 100 сообщений, GCM отклонит это сообщение и отправит специальное сообщение, когда устройства снова подключатся к сети. В этом случае клиент должен выполнить полную синхронизацию с сервером.
Также ознакомьтесь с этим руководством, чтобы начать работу с реализацией клиента CGM.
источник
это отвечает разработчикам, использующим платформу Xamarin (см. /programming/40156342/sync-online-offline-data )
Очень простой способ добиться этого с помощью платформы xamarin - использовать автономную синхронизацию данных Azure, поскольку она позволяет отправлять и извлекать данные с сервера по запросу. Операции чтения выполняются локально, а операции записи - по запросу; Если сетевое соединение разрывается, операции записи ставятся в очередь до восстановления соединения, а затем выполняются.
Реализация довольно проста:
1) создайте мобильное приложение на лазурном портале (вы можете бесплатно попробовать его здесь https://tryappservice.azure.com/ )
2) подключите своего клиента к мобильному приложению. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/
3) код для настройки вашего локального репозитория:
const string path = "localrepository.db"; //Create our azure mobile app client this.MobileService = new MobileServiceClient("the api address as setup on Mobile app services in azure"); //setup our local sqlite store and initialize a table var repository = new MobileServiceSQLiteStore(path); // initialize a Foo table store.DefineTable<Foo>(); // init repository synchronisation await this.MobileService.SyncContext.InitializeAsync(repository); var fooTable = this.MobileService.GetSyncTable<Foo>();
4) затем нажмите и извлеките ваши данные, чтобы убедиться, что у нас есть последние изменения:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/
источник
Предлагаю вам также взглянуть на Симметрики . это библиотека репликации SQLite, доступная для систем Android. вы можете использовать его для синхронизации базы данных клиента и сервера, я также предлагаю иметь отдельные базы данных на сервере для каждого клиента. Попытка хранить данные всех пользователей в одной базе данных mysql - не всегда лучшая идея. Особенно, если объем пользовательских данных будет быстро расти.
источник
Назовем это проблемой CUDR Sync (мне не нравится CRUD, потому что Create / Update / Delete записываются и должны быть соединены вместе)
Проблема также может быть рассмотрена со списания в первую очередь или в режиме онлайн. точки зрения . Подход с автономной записью имеет проблему с конфликтом уникальных идентификаторов, а также с множественными сетевыми вызовами для одной и той же транзакции, увеличивающими риск (или стоимость) ...
Я лично считаю, что подход «сначала пишите в Интернете» проще в использовании (так что он будет единственным источником истины - откуда все остальное синхронизируется). Подход «запись в сети» потребует, чтобы пользователи не позволяли сначала писать в автономном режиме - они будут писать в автономном режиме, получив форму ответа онлайн.
Он может сначала читать в автономном режиме, и как только сеть станет доступной, получить данные из сети и обновить локальную базу данных, а затем обновить пользовательский интерфейс ....
Один из способов избежать конфликта уникальных идентификаторов - это использовать комбинацию из уникального идентификатора пользователя + имени таблицы или идентификатора таблицы + идентификатора строки (сгенерированного sqlite) ... а затем использовать с ним столбец синхронизированного логического флага ... но все же регистрация должна быть выполнена онлайн, чтобы получить уникальный идентификатор, по которому будут сгенерированы все другие идентификаторы ... здесь проблема также будет в том, что часы не синхронизируются, о чем кто-то упоминал выше ...
источник