Управление обслуживанием данных в объектных базах данных, таких как db4o.
-
19-09-2019 - |
Вопрос
Одна вещь, которую я постоянно находил очень запутанной в использовании объектной базы данных, такой как db4o это то, как вы должны обрабатывать сложные миграции, которые обычно обрабатываются SQL/PL-SQL.
Например, представьте, что у вас есть таблица в реляционной базе данных под названием my_users.Первоначально у вас был столбец с именем «полное_имя», теперь, когда ваше программное обеспечение находится в версии V2, вы хотите удалить этот столбец, разделить полные имена на пустое место и поместить первую часть в столбец с именем «первое_имя», а вторую — в столбец. с именем фамилия_фамилия.В SQL я бы просто заполнил столбцы «first_name» и «второе_имя», а затем удалил исходный столбец с именем «full_name».
Как мне это сделать в чем-то вроде db4o?Должен ли я написать программу на Java, которая будет выполнять поиск всех объектов User.class, устанавливая для полного_имени значение null и устанавливая первое_имя и последнее_имя?Когда я сделаю следующий коммит svn, не будет поля/свойства bean-компонента, соответствующего полному_имени, будет ли это проблемой?Кажется, что для использования его в производственном приложении, где меняется моя «схема», я бы хотел написать сценарий для переноса данных из версии x в версию x+1, а затем в версии x+2 фактически удалить свойства, которые я пытаюсь удалить. избавиться для версии x+1, так как я не могу написать сценарий Java для изменения свойств, которые больше не являются частью моего типа.
Кажется, что часть проблемы заключается в том, что СУБД разрешает объект, на который вы ссылаетесь, на основе простого строкового имени, нечувствительного к регистру, на таком языке, как типизация Java, более сложная, чем этот, вы не можете ссылаться на свойство, если метод получения /setter/field не является членом класса, загружаемого во время выполнения, поэтому вам по сути нужно иметь две версии вашего кода в одном и том же скрипте (хм, пользовательские загрузчики классов звучат как боль), чтобы новая версия вашего класса принадлежала другой пакет (звучит беспорядочно) или используйте стратегию версии x+1 x+2, о которой я упоминал (требует гораздо большего планирования).Возможно, есть какое-то очевидное решение, которое я никогда не почерпнул из документов db4o.
Есть идеи?Надеюсь, это имеет какой-то смысл.
Решение
Во-первых, db4o обрабатывает «простые» такие сценарии, как автоматическое добавление или удаление поля..При добавлении поля для всех существующих объектов сохраняется значение по умолчанию.Когда вы удаляете поле, данные существующего объекта все еще остаются в базе данных, и вы по-прежнему можете получить к ним доступ.Поле переименования и т. д. специальные вызовы «рефакторинга».
Теперь в вашем сценарии вы должны сделать что-то вроде этого:
- Удалите поле «полное_имя», добавьте новые поля «первое_имя» и «второе_имя».
- Перебрать все объекты «Адрес»
- Доступ к старому полю через API StoredClass.
- Разделить, изменить, обновить и т. д. значение.Установите новые значения в новом поле и сохраните объект.
Предположим, у нас есть класс «Адрес».Поле «полное_имя» было удалено.Теперь мы не хотим копировать его в «имя» и «фамилия».Тогда это могло бы выглядеть так (Java):
ObjectSet<Address> addresses = db.query(Address.class);
StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class);
for (Address address : addresses) {
String fullName = (String)metaInfoOfField.get(address);
String[] splitName = fullName.split(" ");
address.setFirstname(splitName[0]);
address.setSurname(splitName[1]);
db.store(address);
}
Как вы предложили, вы должны написать код миграции для каждого обновления версии.Если поле больше не является частью вашего класса, вам необходимо получить к нему доступ с помощью API StoredField, как указано выше.
Вы можете получить список всех «сохраненных» классов с помощью ObjectContainer.ext().storedClasses()
.С StoredClass.getStoredFields()
вы можете получить список всех полей магазина, даже если это поле больше не существует в вашем классе.Если класс больше не существует, вы все равно можете получить объекты и получить к ним доступ через класс GenericObject.
Обновлять:Для более сложных сценариев, когда базу данных необходимо перенести за несколько этапов.
Например в версии v3 адрес-объект выглядит совершенно по-другому.Таким образом, в «скрипте миграции» для версии v1 на версию 2 больше нет необходимых полей (в моем примере имя и фамилия).Я думаю, что есть несколько возможностей справиться с этим.
- (Предполагая, что для этой идеи используется Java.Конечно, в .NET есть эквивалент).Вы можете сделать шаг миграции Groovy-скрипт.Чтобы каждый скрипт не мешал другому.Затем вы определяете там «классы» необходимых классов для миграции.Таким образом, каждая миграция имеет свои собственные классы миграции.С псевдонимы вы бы привязали свои классы groovy-migration к реальным Java-классам.
- Создание классов рефакторинга для сложных сценариев.Также свяжите эти классы с псевдонимы.
Другие советы
Здесь я рискую, потому что за свою жизнь я не рефакторил слишком много данных.
Вы делаете странное сравнение:Если вы хотите выполнить «горячую миграцию» базы данных, вам, вероятно, придется выполнить x+1
, x+2
Вы описали подход к управлению версиями, но я действительно не знаю - я тоже не знаю, как это сделать с помощью SQL, поскольку я не эксперт по базам данных.
Однако если вы выполняете «холодную» миграцию, вы можете просто сделать это за один шаг, создав экземпляр нового объекта из старых данных, сохранив новый объект и удалив старый объект для каждого объекта в хранилище.Видеть ссылка на db4o.
А если честно:тот же процесс в СУБД также сложен, потому что вам придется деактивировать проверки ограничений (и, возможно, триггеры и т. д.), чтобы фактически выполнить операцию - возможно, не в приведенном вами примере, но для большинства реальных случаев. .В конце концов, разделение струн настолько простое, что выигрыша будет мало.
В SQL я бы просто заполнил столбцы «first_name» и «второе_имя».
Да, с простой операцию разделения строки, вы можете просто сделай это.Но в типичном сценарии рефакторинга вы реструктурируете объекты на основе больших и сложных наборов правил, которые сложно выразить с помощью SQL, могут потребоваться сложные вычисления или внешние источники данных.
Для этого вам также придется написать код.
В конце концов, я не вижу особой разницы в этих двух процессах.Всегда нужно быть осторожным с живыми данными, и в обоих случаях вы обязательно сделаете резервную копию.Рефакторинг — это весело, но настойчивость — это сложная задача, поэтому синхронизация в любом случае является непростой задачей.