Mantendo a integridade referencial entre um cliente móvel e um servidor

21

Então, eu tenho um sistema relativamente simples. Um cliente móvel cria registros em um banco de dados sqlite que eu gostaria de ter sincronizado com um servidor SQL remoto (que é compartilhado com outros clientes móveis) . Portanto, quando eu crio um novo registro na tabela sqlite do telefone, eu envio essa alteração para o meu serviço remoto por meio de uma API RESTful. O problema que estou tendo é como solicito as chaves primárias para que não ocorram colisões nos dados (ou seja, um registro no telefone tem a mesma chave primária que um registro completamente diferente no servidor). Qual é a "melhor prática usual" para referenciar o registro no cliente e para referenciar o mesmo registro no servidor?

JoeCortopassi
fonte
1
A idéia mais abrangente, seria que o cliente atua como um cache para o servidor web, com as alterações que está sendo criado no cliente, em seguida, empurrou para o servidor web
JoeCortopassi

Respostas:

22

A prática normal é estruturar seu banco de dados com uniqueidentifierchaves (às vezes chamadas de UUIDs ou GUIDs). Você pode criá-los em dois lugares sem medo realista de colisão.

Em seguida, seu aplicativo para celular precisa sincronizar tabelas de "fatos" do servidor antes que você possa criar novas linhas. Ao criar novas linhas, faça-o localmente e, quando sincronizar novamente, novas linhas serão adicionadas ao servidor. Você pode fazer o mesmo com atualizações e exclusões também.

Para rastrear inserções, você precisa de um carimbo de data / hora criado nas suas linhas. Para rastrear atualizações, você precisa acompanhar um carimbo de data e hora do LastUpdate em suas linhas. Para rastrear exclusões, você precisa de uma tabela de marca para exclusão.

Observe que, quando você faz uma sincronização, precisa verificar o deslocamento de tempo entre o servidor e o dispositivo móvel e precisa de um método para resolver conflitos. As inserções não são um grande problema (elas não devem entrar em conflito), mas as atualizações podem entrar em conflito e uma exclusão pode entrar em conflito com uma atualização.

Existem estruturas para lidar com esse tipo de coisa, como o Microsoft Sync Framework .

Scott Whitlock
fonte
é quadro sincronização ainda vivo
Sadaquat
7

Aposto que você absolutamente, sem dúvida, não pode ter integridade referencial entre os dois. Especificamente, seus usuários esperam que o aplicativo móvel funcione quando é desconectado?

Existem duas práticas para isso:

Uma é criar registros "provisórios" no cliente e, quando você os sincronizar com o servidor, o sistema central atribuirá o ID. O cliente pode atualizar o registro local para refletir isso.

A outra é que você distribui a criação do ID de uma maneira que (normalmente de forma probabilística) permita que os clientes criem o ID sem colisões.

Para isso, vá para UUIDs - é improvável que a v4 colida.

Caso contrário, considere algo que coloque o ID exclusivo do dispositivo móvel no ID do registro. Portanto, seu ID de registro pode ser ${imei}-${local sequence number}ou algo assim, onde o IMEI garante exclusividade, e o número de sequência local é apenas um ID sequencial normal do banco de dados.

Daniel Pittman
fonte
2

Além da resposta de Daniel Pittman , uma possibilidade seria o servidor atribuir a cada cliente um ID de cliente exclusivo e fazer dele uma parte da chave primária.

FrustratedWithFormsDesigner
fonte
0

Eu tenho o mesmo problema com um projeto no qual estou trabalhando, a solução no meu caso foi criar um campo anulável extra nas tabelas locais denominadas remote_id. Ao sincronizar registros do banco de dados local para o remoto, se remote_id for nulo, isso significa que essa linha nunca foi sincronizada e precisa retornar um ID exclusivo que corresponda ao ID da linha remota.

Local Table            Remote Table

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

No aplicativo cliente, vinculo tabelas pelo campo _id, remotamente uso o campo de identificação remota para buscar dados, fazer junções, etc.

exemplo 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

exemplo remotamente:

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

Esse cenário, e sem lógica no código, causaria falhas na integridade dos dados, pois a tabela client_type pode não corresponder ao ID real nas tabelas local ou remota; portanto, sempre que um remote_id é gerado, ele retorna um sinal para o aplicativo cliente pedindo para atualizar o campo _id local, isso dispara um gatilho criado anteriormente no sqlite, atualizando as tabelas afetadas. http://www.sqlite.org/lang_createtrigger.html

1- remote_id é gerado no servidor

2- retorna um sinal para o cliente

3- o cliente atualiza seu campo _id e dispara um gatilho que atualiza as tabelas locais que se juntam ao _id local

Claro que também uso um campo last_updated para ajudar nas sincronizações e evitar sincronizações duplicadas.

spacebiker
fonte