Неожиданная Необходимость Управления Версиями Данных

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

решение, требующее минимальных усилий.

Не вдаваясь в подробности конкретного проекта, в котором возникла такая необходимость, представим себе табличный документ Google Docs, редактировать который может любой посетитель сайта.

Предположим, что инженеры Google используют базу данных MySQL следующей структуры: документы --идентификатор --имя --creator_id листы --идентификатор --document_id --имя ряды --число --sheet_id --высота столбцы --число --sheet_id --ширина клетки --идентификатор --sheet_id --цвет --содержание --row_number --col_number --creator_id Как уже было написано выше, доступ к документу имеет любой человек, и, например, изменение значения ячейки на матерное слово навсегда уничтожит предыдущее значение.



Требования к структуре



Обязательный
  • Возможность сохранять предыдущие значения ячеек.

  • Возможность просмотра предыдущих версий онлайн-документа.

  • Возможность отката к предыдущей версии
  • Некоторые параметры могут не иметь разных версий (id,sheet_id)
  • Внедрение в используемый ORM


Желательный
  • Минимально возможные трудозатраты на перенос данных в новую структуру, выбор, изменение и добавление данных
  • Ээкономия дискового пространства
  • Выделение измененных ячеек при просмотре старых редакций


Выполнение

После долгих размышлений была выведена «формула».

Что, если мы создадим дополнительную таблицу и объединим основную таблицу и вновь созданную таблицу, содержащую разные версии значений.

Прежде всего нам нужна таблица с ревизиями: редакции --идентификатор --parent_id --document_id --Дата создания Мы разделили таблицу ячеек на 2, чтобы ячейки содержали информацию, не требующую управления версиями, а ячейки_данные содержали информацию, которая может быть изменена пользователями.

Кроме того, в таблицу cell_data добавляем поля созданный_in_revision_id, delete_in_revision_id и идентификатор пользователя, внесшего изменения.

клетки --идентификатор --sheet_id --row_number --col_number --creator_id ячейки_данные --cell_id --цвет --содержание --data_creator_id --created_in_revision_id --deleted_in_revision_id (первичный ключ для cell_id + созданный_in_revision_id) В нашем коде к объекту Document (если мы программируем на основе объекта) мы добавляем метод getRevisionCondition($revisionId=false), который должен возвращать префикс к SQL-запросу, например «created_in_revision_id in (0,100,300,301) и delete_in_revision_id не в (0,100,300,301)».

Те.

содержать текущую ревизию и всех ее родителей в конструкции «в (.

)» и «не в (.



Образец
Дальше карьер, который раньше выглядел так:
  
  
  
   

select * from cells where row_number=3 and col_number=2

превращается в:

select c.*,cd.* from cells c,cells_data cd where row_number=3 and col_number=2 and id=cell_id and $revisionCondition

Разумеется, имена полей этих таблиц не должны дублироваться.



Вставка новой записи
Здесь все так же просто, как и с семплированием.

Проверяем, не просрочена ли ревизия и берем самую последнюю.

Например вот так:

$revision=$document->updateRevisionIfExpired()

Сначала вставляем в основную таблицу (cells), затем в таблицу с версионными данными (cells_data).

В поле созданный_in_revision_id записываем ID последней ревизии.



Удаление записи
Здесь мы попробуем сэкономить дисковое пространство.

Если, например, мы установили время жизни ревизии 30 минут, то мы сравниваем ревизию удаленной записи с текущей ревизией и:

  • если они совпадают, мы просто удаляем их из базы данных
  • если ревизия уже изменилась, то просто пропишите ID новой ревизии в поле таблицы cell_data — delete_in_revision_id
Для node.js это будет выглядеть так:

if(cellRevisionId==currentRevision.getId()){ db.online.query("delete from cells_data where cell_id="+cellId+" and created_in_revision_id="+cellRevisionId) }else{ db.online.update('cells_data',{'deleted_in_revision_id':currentRevision.getId()},{'cell_id': cellId, 'created_in_revision_id' : cellRevisionId}) }



Обновление записи
Изменение данных чем-то похоже на их удаление.

Если ревизия не изменилась, данные просто обновляются, а если изменились, то поле delete_in_revision_id обновляется и в таблицу cell_data вставляется новая запись с идентификатором новой ревизии в созданном_in_revision_id.

Вместо заключения

Т.

к.

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

Преимущества
  • Все выделения и вставки (другими словами селекты и вставки) были переделаны максимально быстро и без каких-либо осложнений.

  • Делает все что требовалось и почти все что хотелось


Недостатки
  • Удаление и обновление записи по-прежнему немного сложны, и было бы неплохо использовать более автоматизированный скрипт.
  • Возможно, вам нужно что-то сделать с запросами типа in (.

    ), а не in (.

    ), поскольку они перечисляют все версии документа.

Теги: #версия #прослушивание #web 2.0 #web 2.0 #web 2.0 #разработка веб-сайтов
Вместе с данным постом часто просматривают: