Vzor DAO v Jave

1. Prehľad

Vzor Data Access Object (DAO) je štruktúrny vzor, ​​ktorý nám to umožňuje izolovať aplikačnú / obchodnú vrstvu od vrstvy perzistencie (zvyčajne relačnej databázy, ale môže to byť akýkoľvek iný mechanizmus perzistencie) pomocou abstraktného rozhrania API.

Funkcionalita tohto API je skryť pred aplikáciou všetky zložitosti spojené s vykonávaním operácií CRUD v základnom mechanizme úložiska. Toto umožňuje, aby sa obe vrstvy vyvíjali osobitne bez toho, aby ste o sebe niečo vedeli.

V tomto tutoriáli sa hlboko ponoríme do implementácie vzoru a naučíme sa, ako ho používať na abstrahovanie hovorov do správcu entít JPA.

2. Jednoduchá implementácia

Aby sme pochopili, ako vzor DAO funguje, vytvorme si základný príklad.

Povedzme, že chceme vyvinúť aplikáciu, ktorá spravuje používateľov. Aby sme zaistili, že doménový model aplikácie bude v súvislosti s databázou úplne agnostický, vytvoríme ju jednoduchá trieda DAO, ktorá sa postará o to, aby tieto komponenty boli od seba pekne oddelené.

2.1. Trieda domény

Pretože naša aplikácia bude pracovať s používateľmi, musíme na implementáciu jej doménového modelu definovať iba jednu triedu:

public class User {private String name; súkromný reťazcový e-mail; // constructors / standard setters / getters}

The Používateľ class je iba obyčajný kontajner pre údaje používateľov, takže neimplementuje žiadne ďalšie správanie, ktoré stojí za to zdôrazniť.

Samozrejme, najdôležitejšou voľbou dizajnu, ktorú tu musíme urobiť, je spôsob, ako udržať aplikáciu, ktorá používa túto triedu, izolovaný od akýchkoľvek mechanizmov vytrvalosti, ktoré by sa dali v určitom okamihu implementovať.

No, to je presne ten problém, ktorý sa vzor DAO pokúša vyriešiť.

2.2. Rozhranie DAO API

Definujme základnú vrstvu DAO, aby sme videli, ako môže ponechať doménový model úplne oddelený od vrstvy perzistencie.

Tu je rozhranie DAO API:

verejné rozhranie Dao {Voliteľné get (dlhé ID); Zoznam getAll (); neplatnosť uloženia (T t); void update (T t, String [] params); neplatné mazanie (T t); }

Z vtáčej perspektívy je zrejmé, že Dao rozhranie definuje abstraktné API, ktoré vykonáva operácie CRUD na objektoch typu T.

Kvôli vysokej miere abstrakcie, ktorú rozhranie poskytuje, je ľahké vytvoriť konkrétnu, jemnozrnnú implementáciu, ktorá pracuje s Používateľ predmety.

2.3. The UserDao Trieda

Poďme definovať implementáciu Dao rozhranie:

verejná trieda UserDao implementuje Dao {private list users = new ArrayList (); public UserDao () {users.add (new User ("John", "[email protected]")); users.add (new User ("Susan", "[email protected]")); } @Override public Voliteľné get (long id) {návrat Optional.ofNullable (users.get ((int) id)); } @Override public List getAll () {návrat používateľov; } @Override public void save (User user) {users.add (user); } @Override public void update (User user, String [] params) {user.setName (Objects.requireNonNull (params [0], "Name cannot be null")); user.setEmail (Objects.requireNonNull (parametre [1], "E-mail nemôže mať hodnotu null")); users.add (užívateľ); } @Override public void delete (Užívateľský užívateľ) {users.remove (užívateľ); }}

The UserDao trieda implementuje všetky funkcie potrebné na načítanie, aktualizáciu a odstránenie Používateľ predmety.

Pre jednoduchosť, zoznam používateľov funguje ako databáza v pamäti, ktorá je naplnená niekoľkými Používateľ objekty v konštruktore.

Je samozrejme ľahké refaktorovať ostatné metódy, aby mohli pracovať napríklad s relačnou databázou.

Zatiaľ čo obaja Používateľ a UserDao triedy koexistujú nezávisle v rámci tej istej aplikácie, stále musíme vidieť, ako je možné druhú použiť na udržanie vrstvy perzistencie skrytej pred logikou aplikácie:

verejná trieda UserApplication {private static Dao userDao; public static void main (String [] args) {userDao = nový UserDao (); Používateľ user1 = getUser (0); System.out.println (user1); userDao.update (user1, new String [] {"Jake", "[email protected]"}); Používateľ user2 = getUser (1); userDao.delete (user2); userDao.save (nový používateľ ("Julie", "[chránený e-mailom]")); userDao.getAll (). forEach (user -> System.out.println (user.getName ())); } private static User getUser (long id) {Voliteľný užívateľ = userDao.get (id); návrat user.orElseGet (() -> nový používateľ ("neexistujúci používateľ", "žiadny e-mail")); }}

Príklad je vykonštruovaný, ale v skratke ukazuje motiváciu za vzorom DAO. V takom prípade hlavný metóda používa iba a UserDao napríklad na vykonávanie operácií CRUD Používateľ predmety.

Najdôležitejšou stránkou tohto procesu je to, ako UserDao skryje z aplikácie všetky podrobnosti na nízkej úrovni o tom, ako sú objekty perzistentné, aktualizované a mazané.

3. Použitie vzoru pomocou JPA

Medzi vývojármi existuje všeobecná tendencia myslieť si, že vydanie JPA sa znížilo na nulu funkčnosti vzoru DAO, pretože vzor sa stáva iba ďalšou vrstvou abstrakcie a zložitosti implementovanou nad úroveň poskytovanú správcom entít JPA.

Je nepochybné, že v niektorých scenároch to platí. Aj tak, niekedy chceme našej aplikácii vystaviť iba niekoľko metód API správcu entít špecifických pre doménu. V takýchto prípadoch má DAO vzor svoje miesto.

3.1. The JpaUserDao Trieda

S týmto vyjadrením poďme vytvoriť novú implementáciu Dao rozhranie, takže môžeme vidieť, ako môže zapuzdriť funkčnosť, ktorú správca entít JPA poskytuje po vybalení z krabice:

verejná trieda JpaUserDao implementuje Dao {private EntityManager entityManager; // štandardné konštruktory @Override public Voliteľné get (dlhé id) {návrat Voliteľné.ofNullable (entityManager.find (User.class, id)); } @Override public List getAll () {Query query = entityManager.createQuery ("SELECT e FROM User e"); návratový dotaz.getResultList (); } @Override public void save (užívateľský užívateľ) {executeInsideTransaction (entityManager -> entityManager.persist (užívateľ)); } @Override public void update (User user, String [] params) {user.setName (Objects.requireNonNull (params [0], "Name cannot be null")); user.setEmail (Objects.requireNonNull (parametre [1], "E-mail nemôže mať hodnotu null")); executeInsideTransaction (entityManager -> entityManager.merge (užívateľ)); } @Override public void delete (užívateľský užívateľ) {executeInsideTransaction (entityManager -> entityManager.remove (užívateľ)); } private void executeInsideTransaction (akcia spotrebiteľa) {EntityTransaction tx = entityManager.getTransaction (); skus {tx.begin (); action.accept (entityManager); tx.commit (); } catch (RuntimeException e) {tx.rollback (); hod e; }}}

The JpaUserDao trieda je schopná pracovať s akoukoľvek relačnou databázou podporovanou implementáciou JPA.

Ďalej, keď sa na triedu pozrieme pozorne, uvedomíme si, ako nám použitie aplikácie Composition and Dependency Injection umožňuje volať iba metódy správcu entít požadované našou aplikáciou.

Zjednodušene povedané, máme rozhranie API šité na mieru konkrétnej domény, a nie celé rozhranie API správcu entity.

3.2. Prebieha refaktoring Používateľ Trieda

V takom prípade použijeme Hibernate ako predvolenú implementáciu JPA, a preto urobíme refaktoring Používateľ trieda podľa toho:

@Entity @Table (name = "users") verejná trieda User {@Id @GeneratedValue (strategy = GenerationType.AUTO) private long id; súkromné ​​meno reťazca; súkromný reťazcový e-mail; // štandardné konštruktory / setre / getre}

3.3. Zavádzanie správcu entít JPA Programovo

Za predpokladu, že už máme funkčnú inštanciu MySQL spustenú lokálne alebo vzdialene a databázovú tabuľku „Používatelia“ naplnené niektorými záznamami používateľov, musíme získať správcu entity JPA, aby sme mohli použiť JpaUserDao trieda na vykonávanie operácií CRUD v databáze.

Vo väčšine prípadov to dosiahneme pomocou typického „Persistence.xml“ súbor, čo je štandardný prístup.

V tomto prípade si vezmeme „Xml-less“ priblížte sa a získajte správcu entít pomocou jednoduchej Javy prostredníctvom Hibernate's handy EntityManagerFactoryBuilderImpl trieda.

Podrobné vysvetlenie, ako bootovať s implementáciou JPA v prostredí Java, nájdete v tomto článku.

3.4. The UserApplication Trieda

Nakoniec poďme refaktorovať počiatočné UserApplication triedy, takže môže fungovať s a JpaUserDao inštancie a vykonávať operácie CRUD na Používateľ subjekty:

verejná trieda UserApplication {private static Dao jpaUserDao; // štandardné konštruktory public static void main (String [] args) {User user1 = getUser (1); System.out.println (user1); updateUser (user1, new String [] {"Jake", "[email protected]"}); saveUser (nový používateľ („Monica“, „[chránený e-mailom]“))); deleteUser (getUser (2)); getAllUsers (). forEach (užívateľ -> System.out.println (user.getName ())); } public static User getUser (long id) {Voliteľný užívateľ = jpaUserDao.get (id); návrat user.orElseGet (() -> nový používateľ ("neexistujúci používateľ", "žiadny e-mail")); } verejný statický zoznam getAllUsers () {return jpaUserDao.getAll (); } public static void updateUser (užívateľský užívateľ, parametre []; {jpaUserDao.update (užívateľ, parametre); } public static void saveUser (užívateľský užívateľ) {jpaUserDao.save (užívateľ); } public static void deleteUser (užívateľský užívateľ) {jpaUserDao.delete (užívateľ); }}

Aj keď je príklad skutočne dosť obmedzený, zostáva vhodný na preukázanie toho, ako integrovať funkčnosť vzoru DAO s funkciou, ktorú poskytuje správca entít.

Vo väčšine aplikácií existuje DI framework, ktorý je zodpovedný za vstrekovanie a JpaUserDao napríklad do UserApplication trieda. Kvôli jednoduchosti sme vynechali podrobnosti tohto procesu.

Najdôležitejšie je tu zdôrazniť, ako the JpaUserDao trieda pomáha udržiavať UserApplication triedy úplne agnostický o tom, ako vrstva perzistencie vykonáva operácie CRUD.

Okrem toho by sme mohli vymeniť MySQL za akýkoľvek iný RDBMS (a dokonca aj za plochú databázu) ďalej po ceste a naša aplikácia by aj naďalej fungovala podľa očakávania vďaka úrovni abstrakcie poskytovanej Dao rozhranie a správca entity.

4. Záver

V tomto článku sme sa podrobne zamerali na kľúčové koncepty vzoru DAO, ako ich implementovať v Jave a ako ich používať nad správcom entít JPA.

Ako obvykle sú všetky ukážky kódu zobrazené v tomto článku k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found