Управление версиями сохраненных объектов базы данных, как бы вы? - PullRequest
42 голосов
/ 24 сентября 2008

(не относится к управлению версиями схемы базы данных)

Приложения, которые взаимодействуют с базами данных, часто имеют доменные объекты, составленные из данных из многих таблиц. Предположим, что приложение должно поддерживать управление версиями, в смысле CVS, для этих объектов домена.

Для какого-нибудь произвольного объекта домена, как бы вы разработали схему базы данных для удовлетворения этого требования? Есть опыт, которым можно поделиться?

Ответы [ 9 ]

22 голосов
/ 24 сентября 2008

Тщательно продумайте требования к пересмотру. Как только ваша база кода будет иметь всеобъемлющее отслеживание истории, встроенное в операционную систему, она станет очень сложной. Страхование андеррайтинг Системы особенно плохи для этого, поскольку схемы часто работают более 1000 таблиц. Запросы также имеют тенденцию быть довольно сложными, и это может привести к проблемам с производительностью.

Если историческое состояние действительно требуется только для отчетов, рассмотрите возможность внедрения транзакционной системы «текущего состояния» со структурой хранилища данных, висящей сзади для отслеживания истории. Медленно меняющиеся измерения - гораздо более простая структура для отслеживания исторического состояния, чем попытка встроить специальный механизм отслеживания истории непосредственно в вашу операционную систему.

Кроме того, Измененный сбор данных проще для системы «текущего состояния» с изменениями, вносимыми в записи на месте - первичные ключи записей не меняются, поэтому вам не нужно записи матчей, содержащие разные версии одной и той же сущности вместе. Эффективный механизм CDC сделает процесс дополнительной загрузки хранилища достаточно легким и может запускаться довольно часто. Если вам не нужно оперативное отслеживание исторического состояния (почти, но не совсем, и оксюморон), это может быть эффективным решением с гораздо более простой базой кода, чем механизм полного отслеживания истории, встроенный непосредственно в приложение.

12 голосов
/ 24 сентября 2008

Техника, которую я использовал для этого в прошлом, заключалась в том, чтобы иметь понятие «поколения» в базе данных, каждое изменение увеличивает текущий номер поколения для базы данных - если вы используете Subversion, подумайте о пересмотрах. С каждой записью связано 2 номера поколения (2 дополнительных столбца в таблицах) - поколение, для которого начинает действовать эта запись, и поколение, для которого она перестает быть действительной. Если данные в настоящее время действительны, вторым числом будет NULL или какой-либо другой общий маркер.

Итак, чтобы вставить в базу данных:

  1. увеличить номер генерации
  2. вставить данные
  3. помечает время жизни этих данных как действительное значение от и допустимое значение NULL

Если вы обновляете некоторые данные:

  1. пометить все данные, которые будут изменены, как действительные для текущего номера поколения
  2. увеличить номер генерации
  3. вставить новые данные с номером текущего поколения

удаление - это всего лишь вопрос пометки данных как завершающих в текущем поколении.

Чтобы получить конкретную версию данных, найдите, какое поколение вы ищете, и найдите данные, действительные между этими версиями.

Пример:

Создать человека.

|Name|D.O.B  |Telephone|From|To  |
|Fred|1 april|555-29384|1   |NULL|

Обновление № телефона

|Name|D.O.B  |Telephone|From|To  |
|Fred|1 april|555-29384|1   |1   |
|Fred|1 april|555-43534|2   |NULL|

Удалить Фред:

|Name|D.O.B  |Telephone|From|To  |
|Fred|1 april|555-29384|1   |1   |
|Fred|1 april|555-43534|2   |2   |
2 голосов
/ 12 августа 2010

Если вы используете Hibernate, то JBoss Envers может быть вариантом. Вам нужно только аннотировать классы с помощью @Audited, чтобы сохранить их историю.

2 голосов
/ 24 сентября 2008

Альтернативой строгому версионированию является разделение данных на 2 таблицы: текущую и историю.

Текущая таблица содержит все оперативные данные и обладает всеми преимуществами производительности, которую вы создаете. Любые изменения сначала записывают текущие данные в связанную таблицу «истории» вместе с маркером даты, который сообщает, когда они изменились.

1 голос
/ 24 сентября 2008

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

Тогда каждая дочерняя таблица использует идентификатор основной записи + номер версии как часть первичного ключа.

Это можно сделать без мастер-таблицы, но, по моему опыту, это приведет к тому, что операторы SQL станут намного более беспорядочными.

0 голосов
/ 22 ноября 2018

Я не уверен, есть ли у нас такая же проблема, но мне потребовалось большое количество «предложенных» изменений в текущем наборе данных (с цепочками предложений, т. Е. С предложением о предложении).

Подумайте о ветвлении в управлении исходным кодом, но для таблиц базы данных.

Мы также хотели получить исторический журнал, но это был наименее важный фактор - основной проблемой было управление предложениями об изменениях, которые могли зависать в течение 6 месяцев или дольше, поскольку бизнес размышлял над утверждением изменений и готовился к фактическому внедрению изменений. .

Идея состоит в том, что пользователи могут загрузить Изменение и начать создавать, редактировать, удалять текущее состояние данных без фактического применения этих изменений. Отмените любые изменения, которые они могли внести, или отмените все изменение.

Единственный способ добиться этого - это иметь набор общих полей в моих версионных таблицах:

Root ID : Обязательно - задайте один раз первичный ключ при создании первой версии записи. Это представляет первичный ключ за все время и копируется в каждую версию записи. Вы должны учитывать Root ID при именовании столбцов отношения (например, PARENT_ROOT_ID вместо PARENT_ID). Поскольку Root ID также является первичным ключом начальной версии, внешние ключи могут быть созданы для фактического первичного ключа - фактическая желаемая строка будет определяться фильтрами версий, определенными ниже.

Изменение ID : Обязательно - каждая запись создается, обновляется, удаляется с помощью изменения

Скопировано с идентификатора : Nullable - null указывает на вновь созданную запись, not-null указывает, с какого идентификатора записи эта строка была клонирована при обновлении

Действует с даты / времени : Nullable - ноль указывает на предложенную запись, not-null указывает, когда запись стала текущей. К сожалению, уникальный индекс не может быть помещен в Root ID / Effective From, поскольку для любого Root ID может быть несколько нулевых значений. (Если вы не хотите ограничивать себя одним предложенным изменением для каждой записи)

Действует до даты / времени : Nullable - null указывает текущий / предложенный, not-null указывает, когда он стал историческим. Технически не требуется, но помогает ускорить запросы для поиска текущих данных. Это поле может быть повреждено вручную, но в этом случае его можно восстановить из даты и времени вступления в силу.

Удалить флаг : Boolean - установите в значение true, когда предлагается удалить запись после ее появления. Когда удаления фиксируются, для их параметра «Дата вступления в силу / время» устанавливается то же значение, что и для параметра «Дата и время вступления в силу», что позволяет отфильтровать их по текущему набору данных.

Запрос на получение текущего состояния данных в соответствии с изменением будет:

SELECT * FROM table WHERE (CHANGE_ID IN :ChangeId OR (EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now) AND ROOT_ID NOT IN (SELECT ROOT_ID FROM table WHERE CHANGE_ID IN :ChangeId)))

(Фильтрация кратных изменений при изменении производится вне этого запроса).

Запрос на получение текущего состояния данных в определенный момент времени будет:

SELECT * FROM table WHERE EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now)

Общие индексы, созданные для (ROOT_ID, EFFECTIVE_FROM), (EFFECTIVE_FROM, EFFECTIVE_TO) и (CHANGE_ID).

Если кто-нибудь знает лучшее решение, я хотел бы услышать об этом.

0 голосов
/ 03 июня 2015

Как только объект сохранен в базе данных, мы можем изменить его сколько угодно раз. Если мы хотим узнать, сколько раз объект не изменялся, нам нужно применить эту концепцию управления версиями.

Когда мы используем управление версиями, то hibernate вставляет номер версии как ноль, когда объект впервые сохраняется в базе данных. Позднее hibernate автоматически увеличивает эту версию на единицу, когда когда-либо делается модификация для этого конкретного объекта. Чтобы использовать эту концепцию управления версиями, нам нужны следующие два изменения в нашем приложении

Add one property of type int in our pojo class.

In hibernate mapping file, add an element called version soon after id element
0 голосов
/ 24 сентября 2008

ZoDB + ZEO реализует базу данных, основанную на редакции, с полным откатом к любой точке времени поддержки. Иди проверь это.

Плохая часть: это Zope связанный.

0 голосов
/ 24 сентября 2008

Простой надежный способ - добавить столбец версии в ваши таблицы, сохранить версию объекта и выбрать соответствующую логику приложения на основе этого номера версии. Таким образом, вы также получаете обратную совместимость при небольших затратах. Что всегда хорошо

...