Введение
Jmix - фреймворк для создания приложений, ориентированных на работу с данными. Следовательно, модель данных и способы доступа к данным играют ключевые роли. В Jmix для работы с данными используются реляционные БД и JPA.
JPA абстрагирует нас от запросов, специфичных для той или иной СУБД, в приложении же мы работаем с классами и объектами. Но в случае использования JPA необходимо постоянно следить за тем, чтобы схема БД и объектная модель JPA были в согласованном состоянии. В противном случае приложение может даже не запуститься или, что ещё хуже, неожиданно выкинуть ошибку во время работы.
Итак, что мы делаем в Jmix, чтобы избежать подобного и упростить жизнь разработчику?
Немного рассуждений про модель данных
Когда начинается проект (на любом стеке), который использует ORM фреймворк (JPA, iBatis или любой другой), нужно решить, с чего начинать: со схемы базы данных или с объектной модели? В Jmix мы рекомендуем начинать с определения объектной модели. Причина проста: мы определяем типы данных там, где их используем. Поскольку вся бизнес-логика исполняется в приложении, то выглядит логичным определять модель данных именно в приложении.
Приложение - не статическая вещь. Требования бизнеса со временем меняются, соответственно, меняется модель данных. Это значит, что нужно менять схему в хранилище данных.
Времена, когда разработчики сами писали и поддерживали SQL скрипты в своих приложениях, давно прошли. Сейчас почти все используют специальные инструменты для версионирования баз данных. Самые распространенные - Flyway и Liquibase. В Jmix мы используем последний.
Что такое Liquibase?
Официальное определение Liquibase: “Liquibase - решение для управления изменениями схемы базы данных с открытым кодом, которое позволяет управлять ревизиями ваших изменений базы данных”.
Ключевое понятие в Liquibase - “changeset” (набор изменений): одиночное изменение схемы данных. Например, создание таблицы, удаление столбца или изменение правила целостности.
Наборы изменений хранятся в файлах (скриптах, changelogs), в формате, не зависящем от СУБД: XML, YAML или JSON. Можно писать скрипты под определенную СУБД. Например, можно сделать отдельный скрипт для создания столбцов с типом JSONB для PostgreSQL и с типом BLOB для всех остальных.
Обычно в коде приложения создается “основной” (“мастер”) скрипт, содержащий директивы для включения других скриптов, которые находятся в отдельных файлах. И каждый новый скрипт включается в конец основного скрипта.
Liquibase - надежный инструмент для исполнения скриптов изменения схемы БД. Этот инструмент может даже сгенерировать скрипты на основе существующей схемы или на основе разницы двух схем БД. А для Hibernate существует специальный отдельный maven плагин, который может генерировать скрипты на основе объектной модели. Но последнее слово всегда должно оставаться за разработчиком.
Генерация скриптов в Jmix
В Jmix мы генерируем Liquibase скрипты, сравнивая объектную JPA модель данных и схему данных в БД. Цикл разработки по факту состоит из следующих этапов:
- Реализовать объектную модель данных
- Проверить, что все предыдущие скрипты применены к БД
- Сравнить объектную модель со схемой БД
- Сгенерировать Liquibase скрипт, который применяет изменения объектной модели к БД
Выглядит не очень сложно, правда? Фреймворк делает за нас всю грязную работу, нам лишь нужно контролировать процесс. Но нужно быть очень осторожным, потому что не все изменения безопасны. Добавление поля к сущности (т.е. колонки к таблице) - это просто. Но вот удаление поля может привести к потере данных.
Jmix Studio группирует изменения БД и показывает небезопасные красным цветом. Разработчик может убрать изменения из скрипта при необходимости.
Сгенерированные скрипты становятся частью исходного кода. В Jmix мы сохраняем их с группировкой по дате генерации. По умолчанию скрипты сохраняются в файловой системе, в структуре каталогов, как на картинке ниже:
Каждый новый скрипт будет помещен в соответствующий каталог и включен в основной файл changelog.xml
.
Каждый раз, когда Jmix приложение стартует, оно запускает исполнение основного скрипта, используя специальный бин для интеграции Liquibase со Spring Boot.
Процесс миграции базы данных
Во время разработки запускать скрипты Liquibase для обновления рабочей БД можно из Jmix Studio. Надо щелкнуть правой кнопкой мыши на источник данных в навигаторе проекта Jmix и выбрать пункт меню “Update Database”.
А вот в случае развертывания приложения в промышленной эксплуатации мы можем даже не иметь доступа к базе данных. В этом случае у администратора, который занимается развертыванием, есть два варианта:
- Применить скрипты миграции автоматически при старте приложения
- Применить скрипты вручную, а уж затем запустить приложение
Как было сказано ранее, по умолчанию в Jmix приложениях применяется первый вариант. Если же мы не хотим автоматического обновления БД, то необходимо установить свойство jmix.liquibase.enabled
в false
в файле настроек application.properties
.
В Jmix скрипты миграции хранятся в том же JAR файле, что и код приложения. И, хотя Liquibase поддерживает запуск скриптов, упакованных в WAR или EAR файлы, этот инструмент не умеет работать со структурой JAR архива, сгенерированного Spring Boot. Так что, если будет необходимость выполнить скрипты отдельно, нужно будет распаковать архив, скопировать скрипты отдельно и запустить их, используя командную строку Liquibase.
Заключение
Миграция БД - не очень простое занятие. К счастью, есть инструменты, которые сильно облегчают эту задачу. Liquibase предоставляет исполнение скриптов, проверки на повторное выполнение, проверки целостности и т.д.
А с Jmix вы можете генерировать эти скрипты в соответствии с изменениями объектной модели JPA, просматривать их и исправлять, если требуется. Сочетание Jmix и Liquibase покрывает жизненный цикл разработки схемы БД полностью, начиная от разработки JPA модели до обновления схемы БД.