Sprievodca po Jdbi

1. Úvod

V tomto článku sa pozrieme na to, ako dopytovať relačnú databázu pomocou jdbi.

Jdbi je open source knižnica Java (licencia Apache), ktorá používa výrazy lambda a reflexiu na zabezpečenie priateľskejšieho rozhrania na vyššej úrovni ako JDBC na prístup k databáze.

Jdbi však nie je ORM; aj keď má voliteľný modul mapovania objektov SQL, nemá reláciu s pripojenými objektmi, vrstvu nezávislosti databázy a iné zvončeky a píšťalky typického ORM.

2. Nastavenie Jdbi

Jdbi je usporiadané do jadra a niekoľkých voliteľných modulov.

Na začiatok musíme zahrnúť hlavný modul do našich závislostí:

  org.jdbi jdbi3-jadro 3.1.0 

V priebehu tohto článku si ukážeme príklady použitia databázy HSQL:

 org.hsqldb hsqldb 2.4.0 test 

Nájdeme najnovšiu verziu servera jdbi3-jadro, HSQLDB a ďalšie moduly Jdbi na serveri Maven Central.

3. Pripojenie k databáze

Najskôr sa musíme pripojiť k databáze. Aby sme to dosiahli, musíme určiť parametre pripojenia.

Východiskovým bodom je Jdbi trieda:

Jdbi jdbi = Jdbi.create ("jdbc: hsqldb: mem: testDB", "sa", "");

Tu špecifikujeme adresu URL pripojenia, používateľské meno a samozrejme heslo.

3.1. Ďalšie parametre

Ak potrebujeme uviesť ďalšie parametre, použijeme preťaženú metódu akceptujúcu a Vlastnosti objekt:

Vlastnosti vlastnosti = nové Vlastnosti (); properties.setProperty ("používateľské meno", "sa"); properties.setProperty ("heslo", ""); Jdbi jdbi = Jdbi.create ("jdbc: hsqldb: mem: testDB", vlastnosti);

V týchto príkladoch sme uložili Jdbi inštancia v lokálnej premennej. Je to preto, lebo ho použijeme na zasielanie výpisov a dotazov do databázy.

V skutočnosti iba volanie vytvoriť nenadväzuje nijaké spojenie s DB. Iba uloží parametre pripojenia na neskôr.

3.2. Pomocou a Dátový zdroj

Ak sa k databáze pripájame pomocou a Dátový zdroj, ako to zvyčajne býva, môžeme použiť príslušné vytvoriť preťaženie:

Jdbi jdbi = Jdbi.create (zdroj údajov);

3.3. Práca s rukoväťami

Skutočné pripojenia k databáze sú reprezentované inštanciami Rukoväť trieda.

Najjednoduchší spôsob, ako pracovať s rukoväťami a nechať ich automaticky zatvorené, je použitie výrazov lambda:

jdbi.useHandle (handle -> {doStuffWith (handle);});

Voláme useHandle keď nemusíme vracať hodnotu.

Inak používame sHandle:

jdbi.withHandle (handle -> {return computeValue (handle);});

Je tiež možné, aj keď sa to neodporúča, manuálne otvoriť rukoväť pripojenia; v takom prípade ho musíme uzavrieť, keď skončíme:

Jdbi jdbi = Jdbi.create ("jdbc: hsqldb: mem: testDB", "sa", ""); try (Handle handle = jdbi.open ()) {doStuffWith (handle); }

Našťastie, ako vidíme, Rukoväť náradie Uzatvárateľné, takže ho možno použiť so zdrojmi typu try-with-resources.

4. Jednoduché vyhlásenia

Teraz, keď vieme, ako získať pripojenie, sa pozrime, ako ho použiť.

V tejto časti vytvoríme jednoduchú tabuľku, ktorú použijeme v celom článku.

Na zasielanie výpisov ako napr vytvoriť tabuľku do databázy používame vykonať metóda:

handle.execute ("vytvoriť projekt tabuľky" + "(identita celého čísla, meno varchar (50), adresa URL varchar (100))");

vykonať vráti počet riadkov, ktoré boli ovplyvnené výpisom:

int updateCount = handle.execute ("vložiť do hodnôt projektu" + "(1, 'tutoriály', 'github.com/eugenp/tutorials')"); assertEquals (1, updateCount);

Vykonávanie je v skutočnosti iba pohodlná metóda.

Na zložitejšie prípady použitia sa pozrieme v ďalších častiach, ale predtým, ako to urobíme, sa musíme naučiť, ako extrahovať výsledky z databázy.

5. Dotazovanie na databázu

Najpriamočiarejším výrazom, ktorý vytvára výsledky z databázy, je dotaz SQL.

Aby sme mohli zadať dotaz pomocou Jdbi Handle, musíme minimálne:

  1. vytvorte dotaz
  2. zvoliť spôsob zastúpenia každého riadku
  3. iterovať nad výsledkami

Teraz sa pozrieme na každý z vyššie uvedených bodov.

5.1. Vytvorenie dopytu

Neprekvapujúco, Jdbi predstavuje dotazy ako inštancie súboru Dopyt trieda.

Jeden môžeme získať z držadla:

Query query = handle.createQuery ("select * from project");

5.2. Mapovanie výsledkov

Jdbi abstrahuje od JDBC Sada výsledkov, ktorý má dosť ťažkopádne API.

Preto ponúka niekoľko možností prístupu k stĺpcom, ktoré sú výsledkom dotazu alebo iného príkazu, ktorý vracia výsledok. Teraz uvidíme tie najjednoduchšie.

Každý riadok môžeme reprezentovať ako mapu:

query.mapToMap ();

Kľúčmi mapy budú vybrané názvy stĺpcov.

Alebo keď dotaz vráti jeden stĺpec, môžeme ho namapovať na požadovaný typ Java:

handle.createQuery ("vyberte názov z projektu"). mapTo (String.class);

Jdbi má zabudované mapovače pre mnoho bežných tried. Tie, ktoré sú špecifické pre niektorý knižničný alebo databázový systém, sú poskytované v samostatných moduloch.

Môžeme samozrejme tiež definovať a zaregistrovať našich mapovačov. Povieme si o tom v ďalšej časti.

Nakoniec môžeme riadky namapovať na fazuľu alebo inú vlastnú triedu. Pokročilé možnosti opäť uvidíme v vyhradenej sekcii.

5.3. Iterácia nad výsledkami

Keď sme sa rozhodli, ako mapovať výsledky volaním príslušnej metódy, dostávame a Výsledok objekt.

Potom ho môžeme použiť na iteráciu výsledkov po jednom riadku.

Tu sa pozrieme na najbežnejšie možnosti.

Výsledky môžeme iba zhromaždiť do zoznamu:

Zoznam results = query.mapToMap (). list ();

Alebo do iného Zbierka typ:

Zoznam výsledkov = query.mapTo (String.class) .collect (Collectors.toSet ());

Alebo môžeme výsledky iterovať ako prúd:

query.mapTo (String.class) .useStream ((stream stream) -> {doStuffWith (stream)});

Tu sme výslovne zadali znak Prúd premenná kvôli jasnosti, ale nie je to potrebné.

5.4. Získanie jedného výsledku

Ako špeciálny prípad, keď očakávame alebo sa zaujímame iba o jeden riadok, máme k dispozícii niekoľko vyhradených metód.

Ak chceme najviac jeden výsledok, môžeme použiť findFirst:

Voliteľné first = query.mapToMap (). findFirst ();

Ako vidíme, vracia Voliteľné hodnota, ktorá je k dispozícii, iba ak dotaz vráti aspoň jeden výsledok.

Ak dotaz vráti viac ako jeden riadok, vráti sa iba prvý.

Ak namiesto toho chceme jeden jediný výsledok, používame findOnly:

Date onlyResult = query.mapTo (Date.class) .findOnly ();

Nakoniec, ak sú k dispozícii nulové výsledky alebo viac ako jeden, findOnly hodí IllegalStateException.

6. Parametre viazania

Často dotazy majú pevnú časť a parametrizovanú časť. To má niekoľko výhod, medzi ktoré patrí:

  • bezpečnosť: zabránením zreťazenia reťazcov zabránime vloženiu SQL
  • jednoduchosť: nemusíme si pamätať presnú syntax zložitých dátových typov, ako sú časové pečiatky
  • výkon: statickú časť dopytu je možné analyzovať raz a uložiť do medzipamäte

Jdbi podporuje pozičné aj pomenované parametre.

Pozičné parametre vkladáme ako otázniky do dotazu alebo príkazu:

Dotaz positionalParamsQuery = handle.createQuery ("vyberte * z projektu, kde name =?");

Pomenované parametre namiesto toho začínajú dvojbodkou:

Dotaz namedParamsQuery = handle.createQuery ("vyberte * z projektu, kde adresa URL ako: vzor");

V obidvoch prípadoch na nastavenie hodnoty parametra použijeme jednu z variantov parametra viazať metóda:

positionalParamsQuery.bind (0, "návody"); namedParamsQuery.bind ("vzor", "% github.com / eugenp /%");

Upozorňujeme, že na rozdiel od JDBC, indexy začínajú na 0.

6.1. Viazanie viacerých pomenovaných parametrov naraz

Pomocou objektu môžeme tiež spojiť viac pomenovaných parametrov.

Povedzme, že máme tento jednoduchý dopyt:

Dotaz query = handle.createQuery ("vyberte ID z projektu, kde name =: name a url =: url"); Parametre mapy = nový HashMap (); params.put ("meno", "REST s pružinou"); params.put ("url", "github.com/eugenp/REST-With-Spring");

Potom môžeme napríklad použiť mapu:

query.bindMap (parametre);

Alebo môžeme objekt použiť rôznymi spôsobmi. Tu napríklad zviažeme objekt, ktorý sa riadi konvenciou JavaBean:

query.bindBean (paramsBean);

Mohli by sme však tiež viazať polia alebo metódy objektu; všetky podporované možnosti nájdete v dokumentácii Jdbi.

7. Vydávanie zložitejších výpisov

Teraz, keď sme videli dotazy, hodnoty a parametre, sa môžeme vrátiť k príkazom a použiť rovnaké vedomosti.

Pripomeňme, že vykonať metóda, ktorú sme videli predtým, je iba praktická skratka.

V skutočnosti, podobne ako pri dotazoch, Príkazy DDL a DML sú reprezentované ako inštancie triedy Aktualizácia.

Jeden môžeme získať zavolaním metódy createUpdate na rukoväti:

Aktualizácia update = handle.createUpdate ("VLOŽTE DO PROJEKTU (NÁZOV, URL) HODNOTY (: meno,: url)");

Potom na Aktualizácia máme všetky metódy viazania, ktoré máme v a Dopyt, takže časť 6. platí aj pre aktualizácie.url

Výpisy sa vykonávajú, keď voláme, prekvapujeme, vykonať:

int riadky = update.execute ();

Ako sme už videli, vráti počet ovplyvnených riadkov.

7.1. Extrakcia hodnôt stĺpca s automatickým prírastkom

Ako špeciálny prípad, keď máme príkaz vloženia s automaticky generovanými stĺpcami (zvyčajne automatický prírastok alebo sekvencie), možno budeme chcieť získať vygenerované hodnoty.

Potom nezavoláme vykonať, ale executeAndReturnGeneratedKeys:

Aktualizácia update = handle.createUpdate ("VLOŽTE DO PROJEKTU (NÁZOV, URL)" + "HODNOTY ('tutoriály', 'github.com/eugenp/tutorials')"); ResultBearing generatedKeys = update.executeAndReturnGeneratedKeys ();

ResultBearing je rovnaké rozhranie implementované Dopyt trieda ktoré sme už videli predtým, takže už vieme, ako ich používať:

generatedKeys.mapToMap () .findOnly (). get ("id");

8. Transakcie

Transakciu potrebujeme vždy, keď musíme vykonať viac príkazov ako jednu atómovú operáciu.

Rovnako ako v prípade úchytov na pripojenie, aj v tomto prípade zavádzame transakciu volaním metódy s uzáverom:

handle.useTransaction ((Handle h) -> {haveFunWith (h);});

Rovnako ako v prípade rukovätí sa transakcia automaticky uzavrie, keď sa uzávierka vráti.

Musíme však transakciu potvrdiť alebo vrátiť späť pred návratom:

handle.useTransaction ((Handle h) -> {h.execute ("..."); h.commit ();});

Ak je však z uzávierky vyvolaná výnimka, Jdbi transakciu automaticky vráti späť.

Rovnako ako u rukovätí, aj tu máme vyhradenú metódu, inTransaction, ak chceme niečo vrátiť z uzávierky:

handle.inTransaction ((Handle h) -> {h.execute ("..."); h.commit (); return true;});

8.1. Manuálna správa transakcií

Aj keď sa to vo všeobecnosti neodporúča, môžeme tiež začať a Zavrieť transakcia manuálne:

handle.begin (); // ... handle.commit (); handle.close ();

9. Závery a ďalšie čítanie

V tomto tutoriáli sme predstavili jadro Jdbi: dotazy, výpisy a transakcie.

Vynechali sme niektoré pokročilé funkcie, ako je vlastné mapovanie riadkov a stĺpcov a dávkové spracovanie.

Nerozprávali sme sa ani o žiadnom z voliteľných modulov, najmä o rozšírení objektu SQL.

Všetko je podrobne predstavené v dokumentácii Jdbi.

Implementáciu všetkých týchto príkladov a útržkov kódu nájdete v projekte GitHub - jedná sa o projekt Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.