Шаблоны для управления версиями реляционных данных в базе данных MySQL?

12

Я пытаюсь найти подход для проекта, где пользователь может редактировать записи и иметь возможность видеть прошлые версии этих записей. Вот упрощенная схема примера с использованием списка:

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
);

Таким образом, пользователь может войти и внести несколько изменений в список (например, добавить или удалить задачи, изменить порядок задач, отметить некоторые выполненные, переименовать некоторые и т. Д.), А затем сохранить их. На этом этапе я хотел бы создать «версию 2» списка и задач, чтобы они могли просматривать предыдущие версии, но когда они получают доступ к списку, всегда получают последнюю версию.

Существует ли общий подход / шаблон проектирования для работы с данными контроля версий таким образом в базе данных MySQL?

GSto
источник
Обратите внимание, что они библиотеки для этого. Например, если вы используете Hibernate, есть Hibernate Envers. Поэтому, если у вас есть какой-то фреймворк, обрабатывающий DAO, попробуйте поискать, есть ли что-то подобное.
Вальфрат

Ответы:

9

Довольно часто хочется сделать это в БД. Несмотря на то, что вы вносите в него изменения, вы хотите отслеживать изменения для списка элементов.

Одним из способов сделать это может быть изменение структуры, такой как

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...
}

Когда пользователь сохранит свой список, создайте новую ревизию в revisionsтаблице выше и присвойте это значение элементам списка в, list_tasksа затем идентификатору ревизии в, listsчтобы пометить этот идентификатор как «текущую» ревизию. Когда пользователь редактирует элементы, не редактируйте существующие элементы, а вставляйте новые с новым идентификатором ревизии и обновляйте listтаблицу этой ревизией, чтобы пометить ее как текущую.

Затем для отображения текущих элементов перечислите элементы с идентификатором текущей ревизии, указанным в listsтаблице. Для просмотра предыдущих версий вы можете получить список предыдущих ревизий списков из таблицы ревизий, а затем перечислить отдельные элементы на основе этого идентификатора.

GrandmasterB
источник
5

В этом решении используется отдельная таблица аудита. Есть плюсы и минусы. Вы можете предпочесть удалить старые записи из вашей основной таблицы. Улучшение производительности может быть незначительным.

Добавьте следующие поля в каждую проверяемую таблицу:

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

Вам нужно будет обновлять эти поля каждый раз при изменении данных. CurrentVersion увеличивается на 1 (его можно использовать для блокировки записи, но это уже другой вопрос). IsDeleted обеспечивает «мягкое удаление», поэтому на него можно ссылаться в будущем.

Отдельные таблицы аудита Каждая таблица должна иметь соответствующую версию таблицы _Archive или _History. Это, вероятно, не нужно индексировать таким же образом. Очевидно, что одно поле первичного ключа не будет применяться. Вы должны быть в состоянии сделать составной ключ из поля идентификатора и UpdateDateTime.

Использование триггера (Это будет учитывать изменения, сделанные внутри или вне вашего кода. Вы можете решить, подходит ли это для вашей ситуации.) Или другое кодирование: когда запись добавляется, обновляется или удаляется, копия записи помещается в архив Таблица истории. Все версии и другие поля аудита сохраняются. Это скажет вам, что пользователи сделали и когда. Таблицу можно сравнить с самой собой, чтобы увидеть, когда была изменена запись, или увидеть тенденции.

Я хорошо видел эту работу за последние несколько лет. Я хотел бы услышать о недостатках, которые я, возможно, не рассматриваю.

JeffO
источник
Я одобряю это, а также GrandMasterB, оба хороши, и какой из них использовать, зависит от более подробной информации о конкретных потребностях.
Junky
-2

Я бы посоветовал вам прочитать эту подробную статью.

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

Другой подход состоит в том, чтобы иметь столбец version_id в вашей таблице и флаг «current», который указывает, какая строка является текущей. Каждый раз, когда вам нужно обновление, вы можете вставить новую строку и установить для текущей версии флаг 'current' в значение 0 / false, а для новой добавленной строки - 1.

Таким образом, вы можете создать представление, отображающее только те, у которых установлен текущий флаг.

Ehsan
источник