Kihagyás

Liquibase

Az adatbázis verziózásához és az SQL scriptek futtatásához Liquibase -t használunk.

Előnyei:

  • Áttekinthetővé válik, milyen scriptek futottak vagy épp nem futottak le az adatbázison.
  • Az alkalmazás indulása során automatikusan lefuttatja az adatbázis scripteket, azaz a telepítés során nincs szükség manuális script futtatásra.
  • A fentiekből következően a Liquibase azt is garantálja, hogy egy adatbázison minden script garantáltan csak egyszer fusson le.
  • Továbbá az alkalmazás indulása során azt is észleli, ha egy korábban már lefuttatott script tartalmát visszamenőleg módosították.

1. Verziózott adatbázis módosítások

Miután az alkalmazás egy verziója kiadásra kerül, az olyan környezetekre települ, ahol nincs lehetőség az adatbázis struktúra újbóli inicializálására.

Emiatt fontos, hogy minden releaset követő adatbázis módosítás a már létező adatbázis struktúra és adatbázis állapot figyelembevételével történjen.

1.1 Alapelvek

  • Egy már kiadott verzió Liquibase changeSet-jeit tilos módosítani!
  • Ha adatbázis módosításra van szükség egy release után, akkor a következő verzió scriptjei közé kell helyezni a módosító scriptet. (és meghivatkozni a verziószám_master.yml changeLog-ban)!
  • Amennyiben még nincs létrehozva az új verzióhoz changeLog fájl, úgy hozzuk létre a verziónak megfelelő mappát és verziószám_master.yml fájlt!
  • Teszteljük le a korábbi adatbázis állapoton az új scriptjeinket:
    1. A fejlesztés megkezdése és az SQL scriptek írása előtt állítsuk elő azt az adatbázis állapotot, ami ugyanazt tükrözi, mint amin végre fognak hajtódni az új scriptjeink a következő release során!
    2. Lehetőség szerint töltsük fel az adatbázist demó adatokkal, legalább azokat a táblákat, amelyek módosulnak! Ez azért fontos, mert a scriptjeink nem csak az adatbázis struktúrákra vannak hatással, hanem a már létező rekordokra is.
    3. Az új SQL scripteket ezzel az adatbázis állapottal teszteljük!
  • Ügyeljünk arra, hogy a módosításaink kompatibilisek legyenek a már létező adatbázis rekordokkal! (Ebben segítenek a demó adatok.) Pl. Egy oszlop típusának megváltoztatása -> NULLABLE -> NOT NULL esetén migráció lesz szükséges.

Tesztkörnyezet telepítés adatbázis újrainicializálás nélkül

Amennyiben a tesztkörnyezeteken is fontos szempont, hogy ne inicializáljuk rendszeresen újra az adatbázis struktúrát (Pl.: Azt szeretnénk ha nem kellene minden telepítés után újra létrehozni a tesztadatokat.), akkor ajánlott azt az extra szabályt is követni a fejlesztőknek, hogy abban az esetben sem nyúlnak bele a korábbi changeSet-ekbe ha az a tesztkörnyezeten már lefuttatásra került.

Ehelyett ilyen esetben is új changeSet-ben kell hozzáadni az esetleges új scripteket. Még abban az esetben is, ha az új scriptekre a telepítés előtt megírt SQL-ek fixálása miatt van szükség.

1.2 Példa workflow scriptek létrehozására és tesztelésére

  1. Ágazzunk le a develop branchről
  2. Ezen a ponton még ne írjuk meg a scripteket, vagy ha már megtettük, kommentezzük ki a changeSet-et a verziószám_master.yml fájlból.
  3. Futtassuk le a Liquibase scripteket az alkalmazás elindításával (Itt attól függően, hogy min dolgoztunk korábban, fennállhat inkonzisztens állapot, így szükség lehet az adatbázis újrahúzására drop-first: true beállítással)
  4. Írjuk meg a scripteket (vagy ha már korábban megírtuk, de kikommenteztük a changeSet-eket, akkor vegyük le a kommentezést.)
  5. Futtassuk le csak az új SQL scripteket az alkalmazás újraindításával.

Fontos

Az új scriptek futtatásakor drop-first értéke az alkalmazás konfigurációban legyen false -> drop-first : false (vagy ne szerepeljen a konfigban, ugyanis alapértelmezetten false), máskülönben megint újrahúznánk a teljes adatbázist.

Külön Run Configuration drop-first beállítással

A leghasznosabb ha külön Run Configuration-t tartunk fel arra az esetre, ha adatbázis eldobással, vagy eldobás nélkül szeretnénk elindítani az alkalmazást. Részletesebben lásd itt.

2. Konvenciók

2.1 Mappa struktúra

Az adatbázis scriptek alapértelmezetten az src/main/resources/db/changelog mappa alatt találhatóak.

A changelog mappában találhatóak a verzió mappák pl: 1.0.0. Ezek a mappák a nevükből következően az adott verzióhoz tartozó scripteket tartalmazzák. A verzió mappákon belül a script almappába kerülnek maguk az sql fájlok.

2.2 DatabaseChangeLog hierarchia

2.2.1 A db.changelog-master.yaml fájl

A db.changelog-master.yaml a „fő“ DatabaseChangeLog fájlunk, amit a Spring automatikusan megtalál, nem kell explicit módon definiálnunk az elérési útvonalát.

Fontos

Ahhoz, hogy biztosítsuk, hogy a Spring automatikusan megtalálja a db.changelog-master.yaml file-t, a liquibase által ajánlott default mappa struktúrát használjuk.
Fontos, hogy ne módosítsunk a file(db.changelog-master.yaml) és a mappa(db) elnevezésén, mert csak így működik explicit konfiguráció nélkül

A db.changelog-master.yaml fájl az src/main/resources/db/changelog mappa alatt található.

Ebben a fájlban soroljuk fel a verziókhoz tartozó master.yml fájlokat abban a sorrendben, amilyen sorrendben szeretnénk, hogy fussanak az egyes verziókhoz tartozó scriptjeink.

2.2.2 Verziókhoz tartozó master.yml fájlok

A changelog mappa alatti verzió mappákban találhatóak az adott verzióhoz tartozó master.yml fájlok. Pl.: 1.0.0_master.yml

Ebben a fájlban definiáljuk az adott verzió adatbázis scriptjeihez tartozó changeSet-eket, illetve azok futási sorrendjét.

2.3 SQL-fájlok létrehozása

A futtatni kívánt adatbázis scripteket az adott feladat szerint csoportosítjuk és nem aszerint, hogy milyen táblákat érint a script-ekben definiált módosítás.

Ez annyit jelent, hogy fejlesztésenként lehetőség szerint 1 db sql-t kell létrehozni, ami a funkcióhoz/feladathoz tartozó összes scriptet tartalmazza.

Ebből az is következik, hogy az SQL fájlokat nem bontjuk szét DDL és DML utasítások szerint, hanem egy fájlba írjuk őket.

2.4 ChangeSet-ek létrehozása

DDL-ek definiálása

A Semi Product alapértelmezetten yaml changeSet-ekben definiálja a DDL utasításokat. Erre a Semi Product-on azért van szükség, hogy az induló projektek szükség esetén könnyebben tudjanak Postgres-től különböző adatbázis típussal elindulni. Ez azonban a projekten nem elvárás, nyugodtan definiálhatják SQL fájlokban a DDL-eket a fejlesztők.

Minden fejlesztőnek saját changeSet-et kell definiálni, az adott verzióhoz tartozó DatabaseChangeLog fájlon belül.

A scripteket az adott verzió számú mappán belüli script nevű mappába helyezzük el.

Példa egy helyes changeSet definícióra
- changeSet:
    id: 1.2.0:task_short_description
    author: bela.pelda
    changes:
      - sqlFile:
          relativeToChangelogFile: true
          path: script/task_short_description.sql

changeSet konvenciók

  • Az changeSet-ek id-ja legyen prefixelve az aktuális verziószámmal, illetve tömören írja le az adott feladatot, ami miatt a changeSet-et létrehoztuk.
  • Az author-nál mindig adjuk meg a saját nevünket, ami az email címünkben szereplő név kell legyen. Pl.: Ha az email címünk bela.pelda@intuitech.studio akkor az author mezőbe az bela.pelda értéket kell megadni.

2.5 Constraintek létrehozása

Amikor egy tábla oszlopára megszorítást pl.: idegen kulcsot definiálunk, akkor minden esetben definiáljunk a constraint nevét a könnyű módosíthatóság érdekében.

Ha egy constraint nincs explicit elnevezve nehézkes lehet törölni vagy módosítani jövőben, ugyanis olyankor csak egy generált nevet kap.

A helyes formátum constraint létrehozáshoz:

constraintFajtaRövidítés_kulcsotTartalmazóTáblaNev_kulcsotHivatkozóOszlopNév_hivatkozottTáblaNév_hivatkozottOszlopNév

Példák:

  • explicit definiált idegen kulcs név: fk_loan_leasing_id_loan_id
  • generált idegen kulcs név: FK__merchant__partic__22A400A8

Megjegyzés

A fenti két példából jól látszik, hogy a generált név esetén nem fogjuk tudni a név alapján beazonosítani vagy módosítani az idegen kulcsot, míg a kézzel definiált név esetén egyértelműen beazonosítható.

Maximum limit az idegen kulcs neveknél

Az idegenkulcs neveknél vegyük figyelembe, hogy a különböző adatbázisoknál más lehet az idegenkulcs nevek maximális (byte) limitje. Ebből következően érdemes szükség esetén a neveket rövidíteni.

Az alábbi táblázat tartalmazza, hogy az egyes adatbázis típusok max constraint name limitjét:

Adatbázis Max limit (byte)
PostgreSQL 63
SQL Server 128
DB2 128
MySQL 63
Oracle 128

3. Demo adatok kezelése

A demo adatokat nem sql scripteken keresztül állítjuk elő, mert lehet hogy bonyolultabb logikák alapján szeretnénk, amit Java osztályokból könnyebben tudunk létrehozni.

A DemoDataPopulatorService osztály feladata, hogy előállítsa és beszúrja adatbázisba ezeket.

Ezek az adatok csak akkor kerülnek be az adatbázisba, ha az alkalmazás induláskor a demodata profilt is megkapja.

A demo adatokat nem verziózzuk direkt, és mindig ez lesz az utolsó adathalmaz, ami le fog futni.