Mantener integridad referencial entre un cliente móvil y un servidor

21

Entonces tengo un sistema relativamente simple. Un cliente móvil crea registros en una base de datos sqlite que me gustaría sincronizar con un servidor SQL remoto (que se comparte con otros clientes móviles) . Entonces, cuando creo un nuevo registro en la tabla sqlite del teléfono, entonces empujo ese cambio a mi servicio remoto a través de una API RESTful. El problema que tengo es cómo ordenar las claves primarias para que no haya colisiones en los datos (es decir, un registro en el teléfono tiene la misma clave primaria que un registro completamente diferente en el servidor). ¿Cuál es la "práctica recomendada habitual para hacer referencia al registro en el cliente y para hacer referencia al mismo registro en el servidor?

JoeCortopassi
fuente
1
La idea general sería que el cliente actúa como un caché para el servidor web, con cambios que se crean en el cliente y luego se
envían al

Respuestas:

22

La práctica normal es estructurar su base de datos con uniqueidentifierclaves (a veces llamadas UUID o GUID). Puede crearlos en dos lugares sin temor realista de colisión.

A continuación, su aplicación móvil debe sincronizar tablas de "hechos" del servidor antes de que pueda crear nuevas filas. Cuando crea nuevas filas, lo hace localmente, y cuando vuelve a sincronizar, se agregan nuevas filas al servidor. Puede hacer lo mismo con las actualizaciones y eliminaciones también.

Para realizar un seguimiento de las inserciones, necesita una marca de tiempo creada en sus filas. Para rastrear las actualizaciones, debe rastrear una marca de tiempo LastUpdate en sus filas. Para realizar un seguimiento de las eliminaciones, necesita una tabla de lápidas.

Tenga en cuenta que cuando realiza una sincronización, debe verificar el desplazamiento de tiempo entre el servidor y el dispositivo móvil, y debe tener un método para resolver conflictos. Las inserciones no son gran cosa (no deberían entrar en conflicto), pero las actualizaciones podrían entrar en conflicto, y una eliminación podría entrar en conflicto con una actualización.

Hay marcos para manejar este tipo de cosas, como Microsoft Sync Framework .

Scott Whitlock
fuente
es el marco de sincronización sigue vivo
Sadaquat
7

Apuesto a que absolutamente, sin duda , no puede tener integridad referencial entre los dos. Específicamente, ¿esperan sus usuarios que la aplicación móvil funcione cuando está desconectada?

Hay dos prácticas para esto:

Una es crear registros "provisionales" en el cliente, y luego, cuando los sincronice con el servidor, haga que el sistema central asigne la ID. El cliente puede actualizar el registro local para reflejar eso.

El otro es que distribuye la creación de ID de una manera que (normalmente de forma probabilística) permite a los clientes crear la ID sin colisiones.

Para eso, vaya a UUID: es poco probable que v4 choque.

De lo contrario, considere algo que coloque la ID única del dispositivo móvil en la ID del registro. Por lo tanto, su ID de registro puede ser ${imei}-${local sequence number}o algo así, donde el IMEI garantiza la unicidad y el número de secuencia local es solo una ID de base de datos secuencial normal.

Daniel Pittman
fuente
2

Además de la respuesta de Daniel Pittman , una posibilidad sería que el servidor asigne a cada cliente una ID de cliente única y que la ID de cliente forme parte de la clave principal.

FrustratedWithFormsDesigner
fuente
0

Tengo el mismo problema con un proyecto en el que estoy trabajando, la solución en mi caso fue crear un campo anulable adicional en las tablas locales llamadas remote_id. Al sincronizar registros de la base de datos local a la remota si remote_id es nulo, significa que esta fila nunca se ha sincronizado y necesita devolver una identificación única que coincida con la identificación de la fila remota.

Local Table            Remote Table

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

En la aplicación cliente, enlazo tablas por el campo _id, de forma remota uso el campo de identificación remota para obtener datos, hacer uniones, etc.

ejemplo localmente:

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

ejemplo de forma remota:

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

Este escenario, y sin ninguna lógica en el código, causaría fallas en la integridad de los datos, ya que la tabla client_type puede no coincidir con la identificación real en las tablas locales o remotas, por lo tanto, cada vez que se genera un id_remoto, devuelve una señal a la aplicación cliente. pidiendo actualizar el campo local _id, esto dispara un disparador creado previamente en sqlite que actualiza las tablas afectadas. http://www.sqlite.org/lang_createtrigger.html

1- remote_id se genera en el servidor

2- devuelve una señal al cliente

3- el cliente actualiza su campo _id y dispara un disparador que actualiza las tablas locales que se unen al _id local

Por supuesto, también uso un campo last_updated para ayudar a las sincronizaciones y evitar sincronizaciones duplicadas.

motociclista
fuente