Ведение истории изменений данных в базе данных
Каждое изменение данных в некоторой строке в базе данных должно сохранять предыдущие данные строки в какой-то истории, чтобы пользователь мог откатиться к состоянию данных предыдущих строк. Есть ли хорошая практика для такого подхода? Пробовал DataContract, сериализует и десериализует объекты данных, но он становится немного беспорядочным со сложными объектами.
Итак, чтобы быть более ясным:
-
Я использую NHibernate для доступа к данным и хочу оставаться вне зависимости от базы данных (для тестирования с использованием SQL Server 2005)
-
Я намерен предоставить историю данных, поэтому каждый раз, когда пользователь может откатиться к некоторым предыдущим версиям,
Примером использования может быть следующее:
- У меня есть новостная статья.
- Кто-то внесет некоторые изменения в эту статью
- Главный редактор видит, что эта новость имеет некоторые опечатки
- Он решает откат к предыдущей действующей версии (до тех пор, пока не будет исправлена самая новая версия)
Надеюсь, я дал вам достоверную информацию.
Ответы
Ответ 1
Таблицы, в которых хранятся изменения при изменении основной таблицы, называются таблицами аудита. Вы можете сделать это несколькими способами:
- В базе данных с помощью триггеров: Я бы рекомендовал этот подход, потому что тогда невозможно изменить данные без записи. При этом вы должны учитывать три типа изменений: Добавить, Удалить, Обновить. Поэтому вам нужна функция запуска, которая будет работать на всех трех.
Также помните, что транзакция может одновременно изменять несколько записей, поэтому вы должны работать с полным набором измененных записей, а не только с последней записью (как большинство людей запоздало осознали, что сделали).
Элемент управления не будет возвращен вызывающей программе до завершения выполнения триггера. Поэтому вы должны держать код как можно более легким и быстрым.
- В среднем слое с использованием кода:. Этот подход позволит вам сохранить изменения в другой базе данных и, возможно, снять нагрузку с базы данных. Тем не менее, программист SQL, выполняющий инструкцию UPDATE, полностью обходит ваш средний слой, и у вас не будет аудиторского следа.
Структура таблицы аудита
У вас будут следующие столбцы:
Autonumber PK, TimeStamp, ActionType + All columns from your original table
и в прошлом я делал это следующим образом:
Структура таблицы:
Autonumber PK, TimeStamp, ActionType, TableName, OriginalTableStructureColumns
Эта структура будет означать, что вы создадите одну таблицу аудита для каждой таблицы данных. Сохранение и восстановление данных довольно легко сделать. Я бы рекомендовал этот подход.
Параметр имени:
Autonumber PK, TimeStamp, ActionType, TableName, PKColumns, ColumnName, OldValue, NewValue
Эта структура позволит вам сохранить любую таблицу, но вам придется создавать пары значений имени для каждого столбца в триггере. Это очень общее, но дорогое. Вам также нужно будет написать несколько просмотров, чтобы воссоздать фактические строки, не открывая данные. Это становится утомительным и обычно не является методом.
Ответ 2
Вы можете использовать триггеры для этого.
Ниже приведен пример .
AutoAudit is a SQL Server (2005, 2008)
Code-Gen utility that creates Audit
Trail Triggers with:
* Created, Modified, and RowVerwsion (incrementing INT) columns to table
* view to reconstruct deleted rows
* UDF to reconstruct Row History
* Schema Audit Trigger to track schema changes
* Re-code-gens triggers when Alter Table changes the table
http://autoaudit.codeplex.com/
Ответ 3
Microsoft представила новые возможности аудита в SQL Server 2008. Здесь представлена статья, описывающая некоторые возможности и цели проектирования, которые могут помочь в выборе того или иного подхода.
MSDN - Аудит в SQL Server 2008
Ответ 4
Сохранение сериализованных данных всегда становится беспорядочным, вы правы, чтобы держаться подальше от этого. Лучше всего создать параллельную таблицу "версия" с теми же столбцами, что и ваша основная таблица.
Например, если у вас есть таблица с именем "book", с столбцами "id", "name", "author", вы можете добавить таблицу с именем "book_version" с столбцами "id", "name", автор "," version_date "," version_user "
Каждый раз, когда вы вставляете или обновляете запись в таблице "книга", ваше приложение также будет вставляться в "book_version".
В зависимости от вашей системы баз данных и способа доступа к базе данных из вашего приложения вы можете полностью автоматизировать это (cfr плагин Versionable в Doctrine)
Ответ 5
Один из способов - использовать DB, который поддерживает это, например HBase. Обычно я бы не предложил "изменить свой сервер БД для получения этой функции", но поскольку вы не указываете сервер БД в своем вопросе, я предполагаю, что вы подразумеваете это как открытое, а встроенная поддержка на сервере одна из лучших реализаций этой функции.
Ответ 6
Какую систему баз данных вы используете? Если вы используете базу данных ACID (атомарность, согласованность, изоляцию, долговечность), не можете ли вы просто использовать встроенный механизм отката, чтобы вернуться к предыдущей транзакции?
Ответ 7
Я решил эту проблему очень хорошо, используя NHibernate.Enverse
Для тех, кто интересуется:
http://nhforge.org/blogs/nhibernate/archive/2010/07/05/nhibernate-auditing-v3-poor-man-s-envers.aspx