Поддержание ссылочной целостности между мобильным клиентом и сервером

21

Так что у меня относительно простая система. Мобильный клиент создает записи в базе данных SQLite , что я хотел бы синхронизирован на удаленный сервер SQL (который совместно с другими мобильными клиентами) . Поэтому, когда я создаю новую запись в таблице sqlite телефона, я затем отправляю это изменение в свою удаленную службу через RESTful API. Проблема, с которой я столкнулся, заключается в том , как мне упорядочить первичные ключи, чтобы в данных не было коллизий (т. Е. Запись в телефоне имеет тот же первичный ключ, что и совершенно другая запись на сервере). Какова обычная «лучшая практика» для ссылки на запись на клиенте и для ссылки на ту же запись на сервере?

JoeCortopassi
источник
1
Основная идея заключается в том, что клиент выступает в качестве кэша для веб-сервера, при этом изменения создаются в клиенте, а затем
передаются

Ответы:

22

Обычной практикой является структурирование базы данных с помощью uniqueidentifierключей (иногда называемых UUID или GUID). Вы можете создать их в двух местах, не опасаясь столкновения.

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

Чтобы отслеживать вставки, вам нужно создать метку времени в ваших строках. Чтобы отслеживать обновления, вам нужно отслеживать отметку времени LastUpdate в ваших строках. Для отслеживания удалений вам нужна таблица надгробий.

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

Существуют фреймворки для таких вещей, такие как Microsoft Sync Framework .

Скотт Уитлок
источник
Синхронизация еще жива
Sadaquat
7

Могу поспорить, что вы, безусловно, не можете иметь ссылочную целостность между ними. В частности, ожидают ли ваши пользователи, что мобильное приложение будет работать, когда оно отключено?

Для этого есть две практики:

Одним из них является создание «временных» записей на клиенте, а затем при синхронизации их с сервером центральная система назначает идентификатор. Клиент может обновить локальную запись, чтобы отразить это.

Другая причина заключается в том, что вы распространяете создание идентификатора таким образом, который (обычно вероятностно) позволяет клиентам создавать идентификатор без коллизий.

Для этого перейдите к UUID - v4 вряд ли столкнется.

В противном случае рассмотрим что-то, что помещает уникальный идентификатор мобильного устройства в идентификатор записи. Таким образом, ваш идентификатор записи может быть ${imei}-${local sequence number}чем-то вроде того, где IMEI обеспечивает уникальность, а локальный порядковый номер - это просто обычный последовательный идентификатор базы данных.

Даниэль Питтман
источник
2

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

FrustratedWithFormsDesigner
источник
0

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

Local Table            Remote Table

_id (used locally)
remote_id ------------- id
name      ------------- name

В клиентском приложении я связываю таблицы с помощью поля _id, удаленно использую поле удаленного идентификатора для извлечения данных, выполнения объединений и т. Д.

пример локально:

Local Client Table       Local ClientType Table      Local ClientType
                         _id
                         remote_id  
_id -------------------- client_id
remote_id                client_type_id -------------- _id
                                                      remote_id
name                    name                          name

пример удаленно:

Remote Client Table      Remote ClientType Table      Remote ClientType
id -------------------- client_id
                        client_type_id -------------- id
name                    name                          name

Этот сценарий, без какой-либо логики в коде, может привести к сбоям целостности данных, так как таблица client_type может не совпадать с реальным идентификатором в локальной или удаленной таблицах, поэтому всякий раз, когда генерируется remote_id, он возвращает сигнал клиентскому приложению при запросе обновления локального поля _id запускается ранее созданный триггер в sqlite, обновляющий затронутые таблицы. http://www.sqlite.org/lang_createtrigger.html

1- remote_id генерируется на сервере

2- возвращает сигнал клиенту

3 - клиент обновляет свое поле _id и запускает триггер, который обновляет локальные таблицы, которые присоединяются к локальному _id

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

spacebiker
источник