DevCezz

Programistyczny blog dla Ciebie

liquibase
Biblioteki Programowanie

Liquibase

W dzisiejszych czasach ciężko wyobrazić sobie aplikację, która nie przetwarzałaby i przechowywałaby danych do niej dostarczanych. Najczęściej stosowanym pojemnikiem na informacje jest baza danych, którą należy odpowiednio przygotować przed jej użyciem. Wraz z upływem czasu, gdy oprogramowanie będzie rozwijane, niezbędne będzie dokonywanie zmian w schemacie bazy danych. Powszechnie wykorzystuje się do tego celu skrypty SQL zawierające aktualizujące instrukcje. Jednak to rozwiązanie jest mocno uzależnione od czynnika ludzkiego, ponieważ osoba za to odpowiedzialna może wykonać dany skrypt kilka razy lub też zapomnieć w ogóle go uruchomić. Możliwy jest także przypadek, że z jakiejś przyczyny procedura się zatrzyma w trakcie i ciężko będzie dojść co się już wykonało a co nie. Z tego właśnie powodu postanowiono pochylić się nad tym problem i wymyślono narzędzia do zarządzania zmianami na bazie danych. Jednym z nich jest właśnie Liquibase, o którym chciałbym pokrótce napisać w tym artykule.

Czy jest Liquibase?

Sam Liquibase został napisany w Javie i jego głównym zadaniem jest śledzenie, zarządzanie i aplikowanie zmian w schemacie bazy danych. Jego początki sięgają 2006 roku i aktualnie dalej jest rozwijany, obecnie znajduje się w wersji 4.2.2 (grudzień 2020r). Twórcy zapewniają, że Liquibase pozwala w łatwy sposób monitorować zmiany w bazie danych zwłaszcza w środowisku pracy Agile. Jego głównymi funkcjonalnościami są:

  • elastyczna i prosta zmiana schematu – instrukcje mogą być zapisane w formie SQL, XML, YAML czy JSON
  • automatyczne generowanie skryptów SQL – można je zweryfikować tuż po wygenerowaniu, czy na pewno otrzymaliśmy takie zapytania SQL jak chcieliśmy
  • powtarzalne migracje – powtarzalność wykonania na różnych środowiskach, możemy zdecydować, które instrukcje mogą być ponownie wykonywanie podczas uruchomienia a które nie
  • integracja w wieloma narzędziami i bazami danych
  • bezproblemowe wycofanie zmian – automatycznie lub poprzez niestandardowe instrukcje
  • logika wykonania zależna od kontekstu – możliwe jest dostosowanie wykonywanych skryptów
  • monitorowanie w czasie rzeczywistym – darmowy dostęp do Liquibase Hub

No dobrze, ale jak faktycznie może wyglądać plik obsługiwany przez Liquibase? Poniżej przygotowałem te same instrukcje w formacie YAML jak i XML.

Wersja YAML:

databaseChangeLog:
  - changeSet:
      id: create-table-users
      author: devcezz
      preConditions:
        - onFail: MARK_RAN
          not:
            tableExists:
              tableName: users
      changes:
        - createTable:
            columns:
              - column:
                  autoIncrement: true
                  constraints:
                    nullable: false
                    primaryKey: true
                    primaryKeyName: user_pkey
                  name: id
                  type: BIGINT
              - column:
                  constraints:
                    nullable: false
                  name: name
                  type: VARCHAR(250)
              - column:
                  constraints:
                    nullable: false
                  name: age
                  type: BIGINT
            tableName: users

  - changeSet:
      id: add-created-column-to-users
      author: devcezz
      preConditions:
        - onFail: MARK_RAN
          tableExists:
            tableName: users
      changes:
        - addColumn:
            tableName: users
            columns:
              - column:
                  constraints:
                    nullable: false
                  name: createdAt
                  type: DATETIME
                  defaultValueDate: CURRENT_TIMESTAMP

Wersja XML:

<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
			http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

    <changeSet id="create-table-users"
               author="devcezz">
        <preConditions onFail="MARK_RAN">
            <not>
                <tableExists tableName="users"/>
            </not>
        </preConditions>
        <createTable tableName="users">
            <column name="id"
                    type="BIGINT"
                    autoIncrement="true">
                <constraints nullable="false"
                             primaryKey="true"
                             primaryKeyName="user_pkey"/>
            </column>
            <column name="name"
                    type="VARCHAR(250)">
                <constraints nullable="false"/>
            </column>
            <column name="age"
                    type="BIGINT">
                <constraints nullable="false"/>
            </column>
        </createTable>
    </changeSet>

    <changeSet id="add-created-column-to-users"
               author="devcezz">
        <preConditions onFail="MARK_RAN">
            <tableExists tableName="users"/>
        </preConditions>
        <addColumn tableName="users">
            <column name="createdAt"
                    type="DATETIME"
                    defaultValueDate="CURRENT_TIMESTAMP">
                <constraints nullable="false"/>
            </column>
        </addColumn>
    </changeSet>
</databaseChangeLog>

Powyższe przykłady sprowadzają się do dobrze znanych komend SQL. Ich zadaniem jest utworzenie tabeli users zawierającą kolumny id, name i age, a następnie dodanie jeszcze jednej kolumny z datą utworzenia użytkownika.

CREATE TABLE `users` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(250) NOT NULL,
  `age` bigint NOT NULL,
  PRIMARY KEY (`id`)
);

ALTER TABLE `users` ADD `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;

Instrukcje w Liquibase faktycznie są dłuższe niż w SQL, ale jest to cena, którą moim zdaniem warto zapłacić. Zyskujemy w ten sposób pełną automatyzację podczas uruchamiania aplikacji w np. Springu. Nie martwimy się o to czy ktoś zapomni wykonać odpowiednie skrypty aktualizujące posiadając przy tym historię zmian w kolejności chronologicznej.

Podsumowanie

Jak zawsze zachęcam do eksperymentowania ze wszystkimi dostępnymi rozwiązaniami na rynku. Może zapoznanie się z którymś narzędziem pozwoli Ci błysnąć w pracy i wywrzeć wrażenie na przełożonym, czy też ułatwi Ci pracę nad własnym projektem. Ja osobiście jestem na początku drogi zapoznania się z przeróżnymi mechanizmami oferowanymi w naszej branży. Liquibase poznałem w pracy i zacząłem go używać do swojego projektu, który rozwijam w ramach artkułów na ’Przepisz swój kod na nowo!’. Muszę przyznać, że jest to dla mnie ciekawe rozwiązanie, które na pewno ułatwia pracę poprzez automatyzację niektórych zadań. Miałeś bądź miałaś może styczność z podobnym narzędziem? Może masz jakieś inne rozwiązania, które automatyzują pewne procesy? Zapraszam do dyskusji!

Podziel się tym z innymi!