¿Patrones para versionar datos relacionales en una base de datos MySQL?

12

Estoy tratando de encontrar un enfoque para un proyecto, donde un usuario puede editar registros y poder ver versiones anteriores de esos registros. Aquí hay un esquema de ejemplo simplificado, usando una 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
);

Por lo tanto, un usuario puede ingresar y realizar varias ediciones en la lista (es decir, agregar o eliminar tareas, reordenar tareas, marcar algunas completas, cambiar el nombre de algunas, etc.), luego guardarlas. En este punto, me gustaría generar una 'versión 2' de la lista y las tareas, y hacer que puedan ver versiones anteriores, pero cuando acceden a la lista, siempre obtienen la última versión.

¿Existe un patrón de enfoque / diseño común para tratar los datos de versiones de esta manera en una base de datos MySQL?

GSto
fuente
Tenga en cuenta que son bibliotecas para esto. Por ejemplo, si usa Hibernate, hay Hibernate Envers. Entonces, si tiene algún DAO de manejo de framework para usted, intente buscar si hay algo como esto.
Walfrat

Respuestas:

9

Es bastante común querer hacer eso en una base de datos. Aunque le está dando un giro en el sentido de que desea realizar un seguimiento de una revisión de una lista de elementos.

Una forma de hacerlo podría ser alterar la estructura, 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...
}

Cuando el usuario guarda su lista, cree una nueva revisión en la revisionstabla anterior y asigne ese valor a los elementos de la lista list_tasksy luego a la identificación de revisión listspara marcar esa identificación como la revisión 'actual'. Cuando el usuario edite los elementos, no edite los elementos existentes; en su lugar, inserte otros nuevos con un nuevo ID de revisión y actualice la listtabla con esa revisión para marcarla como la actual.

Luego, para enumerar los elementos actuales, enumere los elementos del ID de revisión actual especificado en la liststabla. Para buscar versiones anteriores, puede obtener una lista de revisiones anteriores de las listas de la tabla de revisiones y luego enumerar los elementos individuales en función de esa identificación.

Gran maestro B
fuente
5

Esta solución utiliza una tabla de auditoría separada. Tiene pros y contras. Es posible que prefiera eliminar los registros antiguos de su tabla principal. La mejora del rendimiento puede ser insignificante.

Agregue los siguientes campos a cada tabla auditada:

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

Deberá actualizar estos campos cada vez que cambien los datos. CurrentVersion se incrementa en 1 (podría usarse como una forma de bloquear un registro, pero esa es otra pregunta). IsDeleted proporciona una "eliminación suave" para que pueda ser referenciada en el futuro.

Tablas de auditoría separadas Cada tabla debe tener una versión correspondiente de _Archive o _History de la tabla. Probablemente no sea necesario indexarlos de la misma manera. Obviamente, no se aplicará un solo campo de clave primaria. Debería poder crear una clave compuesta del campo ID y UpdateDateTime.

Usando un disparador (Esto abordará los cambios realizados dentro o fuera de su código. Puede decidir si esto funciona para su situación) u otra codificación, cuando se agrega, actualiza o elimina un registro, se coloca una copia del registro en el archivo / tabla de historial. Se mantienen todas las versiones y otros campos de auditoría. Esto le dirá qué hicieron los usuarios y cuándo. La tabla se puede comparar a sí misma para ver cuándo se modificó un registro o para ver tendencias.

He visto que esto funciona bien en los últimos años. Me gustaría escuchar sobre inconvenientes que tal vez no esté considerando.

JeffO
fuente
Estoy votando tanto esto como GrandMasterB, ambos son buenos y cuál usar depende de más detalles sobre las necesidades específicas.
junky
-2

Te sugiero que leas este artículo bien detallado.

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

Otro enfoque es tener una columna version_id en su tabla y un indicador 'actual' que especifique qué fila es la actual. Cada vez que necesite una actualización, puede insertar una nueva fila y establecer el indicador 'actual' de la versión existente en 0 / falso y la fila recién agregada en 1.

De esta manera, puede crear una vista que muestre solo aquellos con el conjunto de banderas actual.

Ehsan
fuente