Отменить в транзакционной базе данных - PullRequest
3 голосов
/ 13 января 2009

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

С одной стороны, желательно, чтобы пользователь имел возможность многоуровневого (бесконечного) удаления, как указано здесь в ответе. Шаблоны, которые могут помочь в этой проблеме: Memento или Command .

Однако, используя сложную базу данных, включающую триггеры, постоянно растущие порядковые номера и необратимые процедуры, трудно представить, как действие отмены может работать в разных точках, чем границы транзакции. Другими словами, отменить до того момента, когда транзакция, совершенная в последний раз, является просто откатом, но как можно вернуться к другим моментам?

ОБНОВЛЕНИЕ (основываясь на ответах на данный момент): я не обязательно хочу, чтобы отмена работала, когда модификация уже зафиксирована, я бы сосредоточился на работающем приложении с открытой транзакцией. Всякий раз, когда пользователь нажимает «Сохранить», это означает фиксацию, но перед сохранением - во время той же транзакции - отмена должна работать. Я знаю, что использование базы данных в качестве постоянного слоя - это просто деталь реализации, и пользователь не должен беспокоиться об этом. Но если мы думаем, что «идея отмены в базе данных и в GUI - это принципиально разные вещи», и мы не используем отмену в базе данных, то бесконечное удаление - просто модное слово. Я знаю, что «откат - это не отмена пользователя».

Итак, как реализовать отмену на уровне клиента с учетом "каскадных эффектов в результате любых изменений" внутри одной и той же транзакции?

Ответы [ 5 ]

6 голосов
/ 13 января 2009

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

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

4 голосов
/ 13 января 2009

Некоторые (все?) СУБД поддерживают точки сохранения, которые допускают частичные откаты:

savepoint s1;
insert into mytable (id) values (1);
savepoint s2;
insert into mytable (id) values (2);
savepoint s3;
insert into mytable (id) values (3);
rollback to s2;
commit;

В приведенном выше примере останется только первая вставка, остальные две будут отменены.

Я не думаю, что вообще практично пытаться отменить после коммита, по причинам, которые вы указали * и, возможно, другим. Если это необходимо в каком-то сценарии, вам придется создать много кода, чтобы сделать это, и учесть влияние триггеров и т. Д.

  • Хотя я не вижу никаких проблем с постоянно увеличивающимися последовательностями?
2 голосов
/ 13 января 2009

Это почти то же самое, что и пост Уильяма (за который я фактически проголосовал), но я попытаюсь указать немного более подробно, почему необходимо реализовать отмену действий пользователя (по сравнению с использованием отката базы данных).

Было бы полезно узнать больше о вашем приложении, но я думаю, что для пользователя (дружественного) Отменить / Повторить база данных не является достаточным уровнем для реализации этой функции.

  1. Пользователь хочет отменить свои действия независимо от того, приведут ли они к одной / нескольким транзакциям базы данных
  2. Пользователь хочет отменить действия, которые ОН совершил (а не кто-либо другой)

С моей точки зрения, база данных - это детали реализации, инструмент, который вы используете как программист для хранения данных. Откат - это своего рода отмена, которая помогает ВАМ в этом, это не пользовательская отмена. Использование отката означало бы вовлечение пользователя в вещи, о которых он не хочет знать и не понимает (и не должен), что никогда не является хорошей идеей.

Как написал Уильям, вам нужна реализация внутри клиента или на стороне сервера как часть сеанса, которая отслеживает шаги, которые вы определяете как пользовательскую транзакцию, и может отменить их. Если транзакции базы данных были сделаны во время этих пользовательских транзакций, вам нужны другие транзакции БД, чтобы отозвать их (если это возможно). Обязательно предоставьте ценную обратную связь, если отмена невозможна, что снова означает, объясните это с точки зрения бизнеса, а не базы данных.

2 голосов
/ 13 января 2009

Мы разработали такую ​​возможность в нашей базе данных, отслеживая все транзакции, примененные к данным (на самом деле не все, а только те, которым менее 3 месяцев). Основная идея состояла в том, чтобы видеть, кто что и когда делал. Каждая запись в базе данных, уникально идентифицируемая по ее GUID, может затем рассматриваться как результат одного оператора INSERT, нескольких операторов UPDATE и, наконец, одного оператора DELETE. Поскольку мы отслеживаем все эти операторы SQL и поскольку INSERT являются глобальными INSERTS (значение отслеживания всех полей сохраняется в операторе INSERT), то становится возможным:

  • Узнайте, кто и какое поле изменил: Пол вставил новую строку в счет-проформу, Билл пересмотрел цену за единицу товара, Пэт изменил окончательное заказанное количество и т. Д.)
  • 'отменить' все предыдущие транзакции со следующими правилами:

    Отмена 'INSERT' - это 'УДАЛЕНИЕ' на основе уникального идентификатора

    отмена «ОБНОВЛЕНИЕ» эквивалентна предыдущему «ОБНОВЛЕНИЕ»

    Отмена «УДАЛИТЬ» эквивалентна первой ВСТАВКЕ, за которой следуют все обновления

  • Поскольку мы не отслеживаем транзакции старше 3 месяцев, UNDO не всегда доступны.

Доступ к этим функциям строго ограничен только менеджерами баз данных, поскольку другим пользователям запрещено обновлять данные вне бизнес-правил (пример: что означало бы слово «отменить» в строке «Заказ на покупку» один раз) Заказ на поставку был согласован с поставщиком?). Честно говоря, мы используем эту опцию очень редко (несколько раз в год?)

1 голос
/ 13 января 2009

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

Каждая запись имеет флаг «Удалено», номер версии и / или флаг «Текущий индикатор», в зависимости от того, насколько умной вам требуется ваша реконструкция. Кроме того, вам нужен ключ для каждой сущности во всех версиях этой сущности, чтобы вы знали, какие записи фактически ссылаются на какую-то конкретную сущность. Если вам необходимо узнать, когда была применена версия, вы также можете иметь столбцы «От» и «До».

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

Если вам нужна ссылочная целостность (что вы, вероятно, делаете, даже если вы думаете, что нет) и можете справиться с дополнительным вводом / выводом, у вас также должна быть родительская таблица с ключом в качестве заполнителя для записи во всех версии.

В Oracle для этого полезны кластерные таблицы; и родительская таблица, и таблица версий могут быть совмещены, что минимизирует накладные расходы на ввод / вывод. На SQL Server индекс покрытия (возможно, кластеризованный на ключе сущности), включая ключ, уменьшит дополнительный ввод / вывод.

...