Добавление Envers в существующую базу данных

У меня есть приложение на основе Hibernate с большой базой данных. Мне нужно добавить аудит к двум объектам (двум таблицам) в этом приложении, и я решил использовать Envers.

Для каждого INSERT, UPDATE или DELETE Envers добавляет новую запись в таблицу аудита объекта.

Если бы у меня была поддержка Envers с самого начала приложения, таблицы аудита заполнялись бы во время создания сущностей (INSERT).

Документация Envers очень тонкая и ничего не говорит о добавлении Envers в существующее приложение.

Если я просто добавлю поддержку Envers и создам соответствующие таблицы аудита, они начнут пустыми, поэтому, когда я ОБНОВЛЯЮ существующий объект, Envers добавит запись в таблицу аудита, записывающую новые значения, но я потеряю предыдущие значения.

Как мне добавить поддержку Envers в приложение с существующей базой данных?


person Daniel Serodio    schedule 20.03.2013    source источник
comment
Привет! Вы решили свою проблему? у меня тоже такая же проблема..   -  person gipinani    schedule 30.08.2013
comment
Нет, я отказался от Envers и использовал триггеры базы данных ON INSERT и ON UPDATE.   -  person Daniel Serodio    schedule 30.08.2013


Ответы (3)


В настоящее время для этого нет встроенного решения.

«Правильный» способ — написать сценарий SQL (или создать вручную) ревизию «0» вместе со вставкой записей аудита, привязанных к этой ревизии, для каждого существующего объекта.

На самом деле, это довольно часто запрашиваемая функция, поэтому, если вы хотите внести свой вклад, это будет только приветствоваться!

person adamw    schedule 21.03.2013
comment
Поскольку ревизии являются глобальными, а не локальными для конкретного объекта, я боюсь, что добавление нулевой ревизии, влияющей на все сущности, нарушит запрос предыдущих ревизий, поскольку при запросе нулевой ревизии он попытается загрузить всю базу данных, не будет ли это проблемой? - person Daniel Serodio; 21.03.2013
comment
@DanielSerodio Adamw прав. Вы должны добавить ревизию 0 и начать с нее для существующей базы данных. Как узнать предыдущие версии, если в настоящее время аудит не проводится? - person RNJ; 21.03.2013
comment
@RNJ, поскольку вы быстро ответили после моего комментария выше, я не уверен, что вы видели этот комментарий (о глобальной ревизии). Как вы думаете, это будет проблемой? - person Daniel Serodio; 21.03.2013
comment
@DanielSerodio Думаю, ты прав. Но вы бы сделали это? Или вы бы запросили конкретную таблицу в данной ревизии? Вот как я использую его в настоящее время. - person RNJ; 22.03.2013
comment
@RNJ Конечно, я не буду запрашивать все в версии. 0, но я боюсь, что запрос на предыдущую версию объекта E также попытается получить другие объекты. Думаю, мне придется попробовать это в тестовой среде. - person Daniel Serodio; 22.03.2013
comment
Ну а если вы запросите предыдущую ревизию E, то скорее всего добавите id-constraint, который будет загружать только эту одну сущность. Вы получите всю таблицу (нет возможности загрузить всю базу данных), если вы запросите всю таблицу;) - person adamw; 22.03.2013
comment
Я использую spring с envers, и у меня такая же проблема. Я думаю, что решение может состоять в том, чтобы создать проверенный временный объект, а затем скопировать данные из исходной таблицы в проверенный объект. Таким образом envers воссоздает все ревизии. Затем временную таблицу можно удалить, и у нас есть таблица с первоначальными ревизиями. Может это обходной путь или я что-то упустил? Спасибо - person gipinani; 30.08.2013

Вам нужно будет сделать ручные вставки. Что-то типа

INSERT INTO z_envers_revisions (ID, timestamp, user_id, user_name) values (1, round((sysdate - to_date('19700101','YYYYMMDD')) * 86400000) , 42, 'UserName');

INSERT INTO z_Table1(rev, revtype, id, description, name) select 1 as rev, 0 as revtype, id, description, name from Table1;
INSERT INTO z_Table2(rev, revtype, id, description, name) select 1 as rev, 0 as revtype, id, description, name from Table2;

Я поставил перед своими таблицами аудита букву z, чтобы сделать их короче.

person RNJ    schedule 21.03.2013

Что касается envers, основным вариантом использования является запись полного аудита объекта (параметры, которые мы хотим получить с помощью аннотации @Audited). В случае, который вы упоминаете, новые объекты могут быть добавлены правильно, но для существующих это вызовет проблему, поскольку в таблице аудита нет ревизии.

Давайте решим дело с помощью сценария:

Допустим, объект, который мы приняли во внимание, — это пользователи. Таблица, которая создается сейчас для наблюдения за историей, скажем, users_audit. В дополнение к этому также будет использоваться revinfo для наблюдения и записи всех изменений по отношению к данной записи.

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

  1. Вставьте временные значения в таблицу revinfo, чтобы rev могла действовать как внешний ключ.
  2. Скопируйте данные из таблицы users в таблицу users_audit.

Пример файла Liquibase может быть таким:

    CREATE TABLE `revinfo` (
      `rev` int(11) NOT NULL AUTO_INCREMENT,
      `revtstmp` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`rev`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

    INSERT INTO `revinfo` (`revtstmp`) select updated_at from users u;

    SET @position := 0;

    insert into users_audit (
    rev,
    revtype,
    id,
    name,
    type,
    mobile_number,
    password,
    parent_id,
    profile_image_uri,
    is_active,
    created_at,
    updated_at
    ) select @position := @position +1, 0,
    id,
    name,
    type,
    mobile_number,
    password,
    parent_id,
    profile_image_uri,
    is_active,
    created_at,
    updated_at from us
person smutneja03    schedule 01.12.2017