Інструмент створення та керування фізичною моделлю даних Liquibase

🌐 Цей документ доступний українською та англійською мовами. Використовуйте перемикач у правому верхньому куті, щоб змінити версію.

1. Вступ

Платформа для розгортання та супроводження державних електронних реєстрів — це набір конструкторів, кожен з яких виконує певну роль.

Для створення фізичної моделі даних реєстру для СКБД PostgreSQL використовується Liquibase.

Liquibase за замовчуванням підтримує функціональність для розгортання та версіонування об’єктів в базі даних, тобто створення або видалення таблиць, створення зв’язків між цими таблицями, створення views та налаштування обмежень (constraints) тощо.

Для цього Liquibase має власний набір конструкцій — change types, кожна з яких визначає певну версію змін до БД, а формується набором XML-тегів. Наприклад, <createTable>, <dropTable>, тощо.

Оскільки в рамках Платформи реєстрів Liquibase використовується як єдиний інструмент для роботи з фізичною моделлю даних в PostgreSQL, то його стандартної функціональності не достатньо з одного боку, а з іншого — деяка функціональність є надлишковою.

З метою безпеки, БД-розробники або інші категорії користувачів не мають прямого доступу до даних, тобто вони не зможуть виконати SQL-запит до PostgreSQL напряму.
Liquibase має набір впроваджених розширень, які:

2. Запуск Liquibase та розширень

2.1. Що відбувається на стороні Java?

Liquibase - це програмне забезпечення з відкритим кодом, написане мовою Java, що являє собою .jar-файл зі стандартною назвою liquibase.jar.

Архітектура Liquibase дозволяє розробляти розширення (додаткову функціональність) і цю функціональність складати в інший, окремий .jar-файл зі стандартною назвою для розширень — liquibase-ext.jar (в нашому випадку — liquibase-ddm-ext.jar).

2.1.1. Локальний запуск Liquibase та розширень із командного рядка

Для того, аби запрацювали Liquibase та його розширення, необхідно запустити й сам Liquibase, і також підкласти файл з розширеннями в командному рядку.

Локальний запуск Liquibase та розширень із командного рядка для різних середовищ
  • Windows

  • Linux

  • macOS

Java -jar liquibase.jar --driver=org.postgresql.Driver --classpath=postgresql-{version}.jar;liquibase-ddm-ext-{version}.jar --changeLogFile=changeLog.xml --url="jdbc:postgresql://{server_ip}:{server_port}/{db_name}" --username={username} --password={password} --labels="!citus" update -Dbname={db_name}
Java -jar liquibase.jar --driver=org.postgresql.Driver --classpath=postgresql-{version}.jar:liquibase-ddm-ext-{version}.jar --changeLogFile=changeLog.xml --url="jdbc:postgresql://{server_ip}:{server_port}/{db_name}" --username={username} --password={password} --labels="!citus" update -Dbname={db_name}
Java -jar liquibase.jar --driver=org.postgresql.Driver --classpath=postgresql-{version}.jar:liquibase-ddm-ext-{version}.jar --changeLogFile=changeLog.xml --url="jdbc:postgresql://{server_ip}:{server_port}/{db_name}" --username={username} --password={password} --labels="!citus" update -Dbname={db_name}

Оскільки це Java-застосунок, розробник повинен явно вказати наступне:

  • liquibase.jar — файл, який використовується для Liquibase;

  • підключаємося до PostgresSQL, відповідно драйвер має бути org.postgresql.Driver;

  • розширення знаходяться у файлі liquibase-ddm-ext-{version}.jar;

  • changelog, що має застосуватися — changeLog.xml.

  • username та password, для яких має бути створена сесія підключення до БД.

Локальний запуск .jar-файлів з Liquibase та розширеннями Liquibase є зручним для тестових цілей. У промисловому середовищі буде впроваджено автоматизований процес на базі Jenkins pipelines. В такому випадку вихідні XML-шаблони буду завантажуватися до репозитарію з вихідним кодом певного реєстру, звідки Jenkins автоматично відстежуватиме та застосовуватиме зміни.

2.1.2. Changelog та changesets в Liquibase

Changelog - це файл, який містить записи всіх змін, які вносяться до бази даних. Такі зміни називаються changesets. Він може бути оформлений одним окремим файлом — таким чином, що всі зміни до структури БД будуть зазначені в одному файлі, а може складатися з окремих файлів, розташованих за певною ієрархією. Тобто, наприклад, візьмемо файл changeLog.xml. Він може містити найперші "master" changesets на початку, а далі — лише посилання до окремих файлів з атомарними змінами (changesets). В одному такому файлі може бути описано декілька таких змін.

Отже, changelog - набір атомарних змін, які називаються changesets, що наповнюють XML-шаблони, які в результаті перетворюються на SQL-запити та виконуються на цільовій базі даних (див. Створення сценаріїв побудови фізичної моделі даних реєстру за допомогою функціональних розширень Liquibase).

2.1.3. Відновлення попереднього стану (Changeset rollback)

Кожну зміну (changeset) можна "відкотити" до одного з попередніх станів. Для деяких тегів, наприклад, createIndex, rollback реалізований за замовчуванням. Там, де він не реалізований, необхідно в рамках тегу <changeset> додати тег <rollback>.

2.2. Що відбувається на стороні бази даних?

Коли вперше застосовується Liquibase, тобто вперше виконується changelog, Liquibase перевіряє наявність двох службових таблиць:

  • ddm_db_changelog

  • ddm_db_change_loglock

Таблиця ddm_db_changelog зберігає історію застосування changesets в Liquibase. Кожний changeset тут представлений окремим записом.

Найважливіша інформація представлена в колонках id, author та filename, записи в яких зберігають інформацію про ідентифікатор зміни, автора зміни та файл, в якому така зміна застосована.

Таблиця ddm_db_change_loglock використовується для того, щоб Liquibase міг переконатися, що одночасно запущений лише один його екземпляр.

Для чого все це фіксується?

Якщо повторно виконати один і той самий changelog, Liquibase проаналізує, які з changesets цього changelog ще не були застосовані, та застосує тільки їх.

Checksum як додатковий механізм захисту

По кожному changeset рахується checksum, тобто його хеш, що представлений колонкою md5sum.

Якщо адміністратор раптом змінив наявний changeset та намагається виконати його повторно, то Liquibase перевірить колонку exectype та її статус (значення) для цього changeset. Якщо статус EXECUTED (виконано), то Liquibase встановить, що такий changeset вже було виконано, згенерує для нього checksum із поточної версії, яку адміністратор намагається перевиконати, і, коли хеш-суми не збігатимуться, користувач отримає помилку.

Checksum не може збігатися при зміні changeset. Якщо changeset має статус EXECUTED, то він НЕ підлягає модифікації, а лише відновленню до попереднього стану (тобто можна виконати rollback).
Є виключні випадки, коли changeset містить зміни, які постійно еволюціонують. В таких випадках модифікація допускається. Коли changeset застосується повторно, то буде позначений в БД статусом REEXECUTED (перевиконано).