Padrões para controle de versão de dados relacionais em um banco de dados MySQL?

12

Estou tentando encontrar uma abordagem para um projeto, onde um usuário pode editar registros e poder ver versões anteriores desses registros. Aqui está um esquema de exemplo simplificado, usando uma lista:

TABLE list (
  id int auto_increment primary key,
  user_id int, 
  title varchar(255)
);

TABLE list_tasks (
  id int auto_increment primary key,
  list_id int,
  title varchar(255),
  order int,
  is_complete tinyint
);

Para que um usuário possa entrar e fazer várias edições na lista (por exemplo, adicionar ou remover tarefas, reordenar tarefas, marcar algumas como concluídas, renomear outras, etc.), salve-as. Nesse momento, gostaria de gerar uma 'versão 2' da lista e das tarefas e permitir que elas visualizassem versões anteriores, mas, quando acessam a lista, sempre obtêm a versão mais recente.

Existe um padrão comum de abordagem / design para lidar com dados de versionamento dessa maneira em um banco de dados MySQL?

GSto
fonte
Observe que eles são bibliotecas para isso. Por exemplo, se você usa o Hibernate, há Envios do Hibernate. Portanto, se você tiver alguma estrutura manipulando o DAO para você, tente pesquisar se há algo assim.
Walfrat

Respostas:

9

É muito comum querer fazer isso em um banco de dados. Embora você esteja dando uma guinada nisso, você deseja acompanhar uma revisão de uma lista de itens.

Uma maneira de fazer isso pode ser alterar a estrutura, como

Alter table lists add revision_id integer;
Alter table list_tasks add revision_id integer;

Create Table revisions
{
   id int autoincrement... (revision id)
   list_id int...
   revdate datetime...
}

Quando o usuário salvar sua lista, crie uma nova revisão na revisionstabela acima e atribua esse valor aos itens da lista list_taskse, em seguida, ao ID da revisão listspara marcar esse ID como a revisão 'atual'. Quando o usuário editar os itens, não edite os itens existentes. Em vez disso, insira novos com um novo ID de revisão e atualize a listtabela com essa revisão para marcá-la como a atual.

Em seguida, para listar os itens atuais, liste os itens do ID da revisão atual especificado na liststabela. Para procurar versões anteriores, você pode obter uma lista de revisões anteriores das listas na tabela de revisões e, em seguida, listar os itens individuais com base nesse ID.

GrandmasterB
fonte
5

Esta solução usa uma tabela de auditoria separada. Tem prós e contras. Você pode preferir eliminar os registros antigos da sua tabela principal. A melhoria de desempenho pode ser insignificante.

Adicione os seguintes campos a cada tabela auditada:

AddUserID      int <whatever your system uses>
AddDateTime    datetime
UpdateUserID   int <whatever your system uses>
UpdateDateTime datetime
CurrentVersion int
IsDeleted      bit

Você precisará atualizar esses campos sempre que os dados forem alterados. O CurrentVersion é incrementado em 1 (poderia ser usado como uma maneira de bloquear um registro, mas essa é outra questão). IsDeleted fornece uma "exclusão reversível" para que possa ser referenciada no futuro.

Tabelas de auditoria separadas Cada tabela deve ter uma versão _Archive ou _History correspondente da tabela. Provavelmente, eles não precisam ser indexados da mesma maneira. Obviamente, um único campo de chave primária não se aplicará. Você deve conseguir criar uma chave composta fora do campo ID e UpdateDateTime.

Usando um gatilho (Isso abordará as alterações feitas dentro ou fora do seu código. Você pode decidir se isso funciona para a sua situação.) Ou outra codificação, quando um registro é anexado, atualizado ou excluído, uma cópia do registro é colocada no arquivo morto. / tabela de histórico. Todas as versões e outros campos de auditoria são mantidos. Isso informará o que os usuários fizeram e quando. A tabela pode ser comparada consigo mesma para ver quando um registro foi alterado ou para ver tendências.

Vi esse trabalho bem nos últimos anos. Eu gostaria de ouvir sobre as desvantagens que posso não estar considerando.

JeffO
fonte
Estou votando nisso, bem como no GrandMasterB, ambos são bons e qual deles usar depende de mais detalhes sobre as necessidades específicas.
junky
-2

Eu sugiro que você leia este artigo bem detalhado.

https://blog.jondh.me.uk/2011/11/relational-database-versioning-strategies/comment-page-1/#comment-373850

Outra abordagem é ter uma coluna version_id na sua tabela e um sinalizador 'current' que especifique qual linha é a atual. Cada vez que você precisar de uma atualização, poderá inserir uma nova linha e definir o sinalizador 'atual' da versão existente como 0 / false e a linha recém-adicionada como 1.

Dessa forma, você pode criar uma exibição mostrando apenas aqueles com o conjunto de sinalizadores atual.

Ehsan
fonte