Při programování databázových aplikací narazíte na problém, kam uložit primární schéma databáze. Existuje k němu několik přístupů:
- na centrálním databázovém serveru
- v SQL skriptech se zdrojáky
- Hibernate schemaupdate s upgrade skripty
Na centrálním databázovém serveru
Tento přístup je nejjednodušší – prostě používáte jeden centrální databázový server a změny provádíte přímo zde.
Nevýhodou tohoto řešení je sledování změn a historie. Řešením je při každém vydání verze uložení do verzovacího systému. Také nastávají problémy, pokud pro vás není vhodné řešení JEDNOHO centrálního serveru (vzdálený přístup, offline).
SQL skripty se zdrojáky
Tentokrát ukládáme SQL skripty spolu se zdrojáky. Vývojař nahraje aktuální verzi z SQL skriptů do databáze. Sledování změn je prováděno na úrovni SQL skriptů. Nevýhodou je doba nahrávání dat, případně zachování testovacích dat v databázi. Toto řešení může způsobovat problémy, pokud používá jeden databázový server více vývojařů (jsou nezbytné změny již zaneseny?).
Hibernate schemaupdate s upgrade skripty
Toto řešení se nám osvědčilo nejlépe. Datový model máme zapsán v mapovacích souborech Hibernate (resp. JPA). Při startu aplikace použijeme nastavení hbm2ddl.auto=update a Hibernate zkontroluje, zda existují všechny tabulky, položky tabulek a zda jsou správného typu a existenci cizích klíčů. Pokud schéma neodpovídá modelu, dokáže provést změny automaticky.
Hibernate samozřejmě nedokáže převádět data (např. přesunutí sloupce do vlastní tabulky) a ani některé typy operací (např. smazání položky, entita není uložena jako tabulka, ale view, …). K tomu udržujeme tzv. upgrade skripty. Jednoduchý SQL skript, který provede požadovanou změnu a navíc do zvláštní tabulky (tabulka provedených změn databáze) zapíše datum a číslo upgrade skriptu tak je zaručené, že nelze pustit jeden upgrade skript opakovaně (jedinečnost čísla upgrade skriptu). Díky této tabulce, lze z aplikace tak zkontrolovat zda tak bylo provedeno (v aplikaci máme zakompilovanou minimální požadovanou „verzi“ schématu databáze).
Programátor si tedy zaktualizuje zdrojáky, zkompiluje a pustí &nbash; pokud je potřeba nějaká změna schématu, je na to aplikací vždy upozorněn (případně je možné změny nahrát automaticky aplikací). Osvědčilo se nám, vždy nejdříve zaktualizovat databázi pomocí Hibernate a pak až pouštět upgrade skripty.
Toto řešení má tyto výhody:
- databáze je vždy v takovém stavu, aby bylo možné pustit aplikaci
- nepřijdete o testovací data
- je možné téměř z každé verze přejít libovolně výš (např. u zákazníka)
- změny, které nemůže provést Hibernate, provedeme v upgrade skriptu
a také nevýhody:
- Hibernate nedokáže změnit nulovatelnost (NULL, NOT NULL). Proto jsme si vytvořili jednoduchý nástroj, který nám dokáže zkontrolovat databázi oproti schématu Hibernate.
- Hibernate nedokáže provést všechny operace (např. výše uvedené mazání položky) řešíme upgrade skriptem
- není vhodné, pokud nesmíte měnit schéma databáze
- není vhodné, pokud máte existující schéma a jen k němu píšete aplikaci (ale i tehdy je možné jej použít např. v kombinaci jednorázovým puštěním s generátoru mapování a Java souborů podle existující databáze)
- zpomaluje se start aplikace zjištění, že je schéma aktuální trvá několik vteřin (akci tedy u vývojařů neprovádíme při startu aplikace, ale na vyžádání)
- databázové schéma je natolik svázané z databází (mnoho triggerů, view, …), že většina změn není v datových tabulkách – v takovém případě nemusí být přínos příliš velký
Jedním z argumentů, který často slýchám proti tomuto řešení je, že lidé nedůvěřují schopnostem Hibernate vytvořit schéma. Vždy, ale máte možnost upravit mapování Hibernate tak, aby databáze vypadala přesně tak jak chcete vy. Navíc, protože je schéma nové, nemusíte téměř nikdy upravovat mapování – Hibernate sám navrhne jména sloupců, typy a případně délky.
Cílem je, že udržujete vždy jen jedno datové schéma na jednom místě. Nemusíte vždy upravit schéma v databázi, upravit Java soubory a upravit mapování (protože v databázi bude název zaručeně jinak než v Javě :-)).
V našem případě jsme celé řešení rozšířili tak, že datový model (řekněme konceptuální model) navrhujeme v UML kreslítku (ArgoUML). U vazeb definujeme mohutnost (např. N:N). Pak z UML modelu pomocí nástroje AndroMDA, vygenerujeme Java soubory a mapování, kde je převeden model do fyzického schématu databáze – např. vazba N:N na vazební tabulku a dvě vazby 1:N.
Výsledkem tohoto přístupu je jednoduchost a rychlost vývoje, která zároveň umožňuje velkou flexibilitu v případě, že „výchozí“ výsledek není dostatečný.
Ještě bych zmínil další výhody **SchemaUpdate**:
– je bundled s hibernate core library
– lze jsi spouště nezávisle pomocí Ant tasku nebo přímo z java kódu