Maintenir l'intégrité référentielle entre un client mobile et un serveur

21

J'ai donc un système relativement simple. Un client mobile crée des enregistrements dans une base de données sqlite que j'aimerais synchroniser avec un serveur SQL distant (partagé avec d'autres clients mobiles) . Ainsi, lorsque je crée un nouvel enregistrement dans la table sqlite du téléphone, j'appuie ensuite cette modification sur mon service distant via une API RESTful. Le problème que je rencontre est de savoir comment commander les clés primaires afin qu'il n'y ait pas de collision dans les données (c'est-à-dire qu'un enregistrement dans le téléphone a la même clé primaire qu'un enregistrement complètement différent sur le serveur). Quelle est la «meilleure pratique habituelle pour référencer l'enregistrement sur le client et pour référencer le même enregistrement sur le serveur?

JoeCortopassi
la source
1
L'idée générale serait que le client agit comme un cache pour le serveur Web, avec des modifications étant créées dans le client, puis poussées vers le serveur Web
JoeCortopassi

Réponses:

22

La pratique normale consiste à structurer votre base de données avec des uniqueidentifierclés (parfois appelées UUID ou GUID). Vous pouvez les créer à deux endroits sans crainte réaliste de collision.

Ensuite, votre application mobile doit synchroniser les tables de "faits" du serveur avant de pouvoir créer de nouvelles lignes. Lorsque vous créez de nouvelles lignes, vous le faites localement et lorsque vous effectuez une nouvelle synchronisation, de nouvelles lignes sont ajoutées au serveur. Vous pouvez également faire la même chose avec les mises à jour et les suppressions.

Pour suivre les insertions, vous avez besoin d'un horodatage créé sur vos lignes. Pour suivre les mises à jour, vous devez suivre un horodatage LastUpdate sur vos lignes. Pour suivre les suppressions, vous avez besoin d'une table tombstone.

Notez que lorsque vous effectuez une synchronisation, vous devez vérifier le décalage horaire entre le serveur et le périphérique mobile, et vous devez disposer d'une méthode pour résoudre les conflits. Les insertions ne sont pas un gros problème (elles ne devraient pas entrer en conflit), mais les mises à jour peuvent entrer en conflit et une suppression peut entrer en conflit avec une mise à jour.

Il existe des cadres pour gérer ce genre de choses, tels que Microsoft Sync Framework .

Scott Whitlock
la source
est le cadre de synchronisation toujours en vie
Sadaquat
7

Je parie que vous absolument, sans question ne peut pas avoir l' intégrité référentielle entre les deux. Plus précisément, vos utilisateurs s'attendent-ils à ce que l'application mobile fonctionne lorsqu'elle est déconnectée?

Il existe deux pratiques pour cela:

L'une consiste à créer des enregistrements "provisoires" sur le client, puis lorsque vous les synchronisez avec le serveur, le système central attribue l'ID. Le client peut mettre à jour l'enregistrement local pour refléter cela.

L'autre est que vous distribuez la création d'ID d'une manière qui (normalement de manière probabiliste) permet aux clients de créer l'ID sans collision.

Pour cela, accédez aux UUID - il est peu probable que la v4 entre en collision.

Sinon, envisagez quelque chose qui place l'ID d'appareil mobile unique dans l'ID d'enregistrement. Ainsi, votre ID d'enregistrement peut être ${imei}-${local sequence number}ou quelque chose, où l'IMEI garantit l'unicité et le numéro de séquence local est juste un ID de base de données séquentielle normal.

Daniel Pittman
la source
2

En plus de la réponse de Daniel Pittman , une possibilité serait que le serveur attribue à chaque client un ID client unique et fasse de l'ID client une partie de la clé primaire.

FrustratedWithFormsDesigner
la source
0

J'ai le même problème avec un projet sur lequel je travaille, la solution dans mon cas était de créer un champ nullable supplémentaire dans les tables locales nommé remote_id. Lors de la synchronisation des enregistrements de la base de données locale vers la base de données distante si remote_id est null, cela signifie que cette ligne n'a jamais été synchronisée et doit renvoyer un ID unique correspondant à l'ID de la ligne distante.

Local Table            Remote Table

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

Dans l'application client, je relie les tables par le champ _id, à distance j'utilise le champ id distant pour récupérer des données, faire des jointures, etc.

exemple localement:

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

exemple à distance:

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

Ce scénario, et sans logique dans le code, entraînerait des échecs d'intégrité des données, car la table client_type peut ne pas correspondre à l'id réel dans les tables locales ou distantes, donc chaque fois qu'un remote_id est généré, il renvoie un signal à l'application cliente demandant de mettre à jour le champ _id local, cela déclenche un déclencheur précédemment créé dans sqlite mettant à jour les tables affectées. http://www.sqlite.org/lang_createtrigger.html

1- remote_id est généré sur le serveur

2- renvoie un signal au client

3- Le client met à jour son champ _id et déclenche un déclencheur qui met à jour les tables locales qui rejoignent le _id local

Bien sûr, j'utilise également un champ last_updated pour faciliter les synchronisations et éviter les synchronisations en double.

Spacebiker
la source