A DAO minta Java-ban

1. Áttekintés

Az Data Access Object (DAO) minta egy strukturális minta, amely lehetővé teszi számunkra izolálja az alkalmazás / üzleti réteget a perzisztencia rétegtől (általában relációs adatbázisból, de ez bármilyen más perzisztencia mechanizmus is lehet) absztrakt API használatával.

Ennek az API-nak az a funkciója, hogy elrejtse az alkalmazás alól az összes összetettséget, ami a CRUD műveletek elvégzéséhez kapcsolódik az alapul szolgáló tárolási mechanizmusban. Ez lehetővé teszi mindkét réteg különálló fejlődését anélkül, hogy bármit is tudnának egymásról.

Ebben az oktatóanyagban mélyen elmélyülünk a minta megvalósításában, és megtanuljuk, hogyan kell használni a JPA entitáskezelőhöz intézett hívások elvonatkoztatásához.

2. Egyszerű megvalósítás

Készítsünk egy alap példát, hogy megértsük a DAO minta működését.

Tegyük fel, hogy olyan alkalmazást szeretnénk kifejleszteni, amely kezeli a felhasználókat. Létrehozzuk, hogy az alkalmazás tartománymodellje teljes mértékben agnosztikus maradjon az adatbázissal kapcsolatban egy egyszerű DAO osztály, amely gondoskodik ezen alkatrészek szép szétválasztásáról.

2.1. A Domain osztály

Mivel alkalmazásunk a felhasználókkal fog működni, csak egy osztályt kell meghatároznunk a tartománymodell megvalósításához:

public class Felhasználó {private String name; privát karakterlánc e-mail; // konstruktorok / standard beállítók / szerelők}

A Felhasználó osztály csak egy egyszerű tároló a felhasználói adatok számára, ezért nem hajt végre más, hangsúlyozni érdemes viselkedést.

Természetesen a legrelevánsabb tervezési választás, amelyet itt meg kell tennünk, az, hogy miként lehet az osztályt használó alkalmazást elkülöníteni minden olyan perzisztencia-mechanizmustól, amely valamikor megvalósítható.

Nos, pontosan ezzel a kérdéssel próbálkozik a DAO minta.

2.2. A DAO API

Definiáljunk egy alap DAO réteget, hogy lássuk, hogyan tud tartsa a tartománymodellt teljesen leválasztva a perzisztencia rétegtől.

Itt van a DAO API:

nyilvános felület Dao {Opcionális get (hosszú id); List getAll (); érvénytelen mentés (T t); void frissítés (T t, String [] paraméterek); érvénytelen törlés (T t); }

Madártávlatból egyértelmű, hogy a Dao Az interfész egy absztrakt API-t határoz meg, amely CRUD műveleteket hajt végre típusú objektumokon T.

Az interfész magas szintű absztrakciójának köszönhetően könnyű konkrét, finom szemcsés megvalósítást létrehozni, amely működik Felhasználó tárgyakat.

2.3. A UserDao Osztály

Határozzuk meg a felhasználó felhasználóspecifikus megvalósítását Dao felület:

public class A UserDao megvalósítja a Dao {private List users = new ArrayList (); public UserDao () {users.add (new User ("John", "[email protected]")); users.add (új felhasználó ("Susan", "[e-mail védett]")); } @Orride public Opcionális get (hosszú id) {return Optional.ofNullable (users.get ((int) id)); } @Orride public list getAll () {visszatérő felhasználók; } @Orride public void save (Felhasználói felhasználó) {users.add (user); } @Orride public void update (Felhasználói felhasználó, String [] paraméterek) {user.setName (Objects.requireNonNull ([0] paraméterek, "A név nem lehet null")); user.setEmail (Objects.requireNonNull ([1] paraméter, "Az e-mail nem lehet null")); users.add (felhasználó); } @Orride public void delete (Felhasználói felhasználó) {users.remove (Felhasználó); }}

A UserDao osztály megvalósítja a beolvasáshoz, frissítéshez és eltávolításhoz szükséges összes funkciót Felhasználó tárgyakat.

Az egyszerűség kedvéért a felhasználók listája úgy viselkedik, mint egy memóriában lévő adatbázis, amely párral van feltöltve Felhasználó objektumok a konstruktorban.

Természetesen könnyű átalakítani a többi módszert, így például egy relációs adatbázissal működhetnek.

Míg mind a Felhasználó és UserDao osztályok egymástól függetlenül léteznek ugyanazon alkalmazáson belül, még mindig meg kell látnunk, hogy az utóbbiak hogyan használhatók a perzisztencia réteg rejtve tartására az alkalmazás logikája elől:

public class UserApplication {privát statikus Dao userDao; public static void main (String [] args) {userDao = new UserDao (); User1 = getUser (0); System.out.println (user1); userDao.update (user1, új karakterlánc [] {"Jake", "[email protected]"}); User2 = getUser (1); userDao.delete (user2); userDao.save (új felhasználó ("Julie", "[e-mail védett]")); userDao.getAll (). forEach (felhasználó -> System.out.println (user.getName ())); } privát statikus felhasználó getUser (hosszú azonosító) {Opcionális felhasználó = userDao.get (id); return user.orElseGet (() -> new User ("nem létező felhasználó", "no-email")); }}

A példa kitalált, de dióhéjban megmutatja a DAO minta mögött meghúzódó motivációkat. Ebben az esetben a fő- módszer csak a UserDao például CRUD műveletek elvégzésére néhány Felhasználó tárgyakat.

Ennek a folyamatnak a legfontosabb aspektusa a hogyan UserDao elrejti az alkalmazásból az összes alacsony szintű részletet arról, hogy az objektumok hogyan maradnak fenn, frissülnek és törölhetők.

3. A minta használata a JPA-val

A fejlesztők körében általános tendencia, hogy azt gondolják, hogy a JPA kiadása a DAO minta funkcionalitását nullára csökkentette, mivel a minta csak az absztrakció és komplexitás újabb rétegévé válik, amelyet a JPA entitásmenedzsere biztosít.

Kétségtelen, hogy egyes esetekben ez igaz. Még akkor is, néha csak az entitáskezelő API néhány tartományspecifikus módszerét szeretnénk kitenni alkalmazásunknak. Ilyen esetekben a DAO mintának a helye.

3.1. A JpaUserDao Osztály

Ezzel elmondva hozzunk létre egy új megvalósítást a Dao interfész, így láthatjuk, hogyan tudja a JPA entitáskezelője a dobozból beilleszteni a funkciókat:

a JpaUserDao nyilvános osztály megvalósítja a Dao {private EntityManager entitásManagert; // szabványos konstruktorok @Orride public Opcionális get (hosszú id) {return Optional.ofNullable (entitásManager.find (Felhasználó.osztály, id)); } @Orride public list getAll () {Query query = entitásManager.createQuery ("SELECT e FROM User e"); return query.getResultList (); } @Orride public void save (User user) {executeInsideTransaction (entitásManager -> entitásManager.persist (felhasználó)); } @Orride public void update (User user, String [] params) {user.setName (Objects.requireNonNull (params [0], "A név nem lehet null")); user.setEmail (Objects.requireNonNull ([1] paraméter, "Az e-mail nem lehet null")); executeInsideTransaction (entitásManager -> entitásManager.merge (felhasználó)); } @Orride public void delete (Felhasználói felhasználó) {executeInsideTransaction (entitásManager -> entitásManager.remove (felhasználó)); } private void executeInsideTransaction (fogyasztói művelet) {EntityTransaction tx = entitásManager.getTransaction (); próbáld meg {tx.begin (); action.accept (entitásManager); tx.commit (); } catch (RuntimeException e) {tx.rollback (); dobja e; }}}

A JpaUserDao osztály képes bármilyen, a JPA megvalósítása által támogatott relációs adatbázissal dolgozni.

Továbbá, ha alaposan szemügyre vesszük az osztályt, rájövünk, hogy a Kompozíció és Függőség Injekció használata lehetővé teszi-e, hogy csak az alkalmazásunk által megkívánt entitáskezelő módszereket hívjuk meg.

Egyszerűen fogalmazva, egy tartományspecifikusan szabott API-val rendelkezünk, nem pedig az entitásmenedzser teljes API-jával.

3.2. A Felhasználó Osztály

Ebben az esetben a hibernált módot fogjuk használni a JPA alapértelmezett megvalósításaként, így átalakítjuk a Felhasználó osztály ennek megfelelően:

@Entity @Table (name = "users") public class User {@Id @GeneratedValue (strategy = GenerationType.AUTO) private long id; privát karakterlánc neve; privát karakterlánc e-mail; // szabványos kivitelezők / beállítók / szerelők}

3.3. Bootstrapping JPA Entity Manager Programozatosan

Feltéve, hogy már van egy működő MySQL példányunk, amely lokálisan vagy távolról fut, és egy adatbázis tábla „Felhasználók” néhány felhasználói rekorddal feltöltve beszereznünk kell egy JPA entitáskezelőt, így használhatjuk a JpaUserDao osztály CRUD műveletek végrehajtására az adatbázisban.

A legtöbb esetben ezt a tipikuson keresztül valósítjuk meg “Persistence.xml” fájl, amely a szokásos megközelítés.

Ebben az esetben veszünk egy „Xml nélküli” Hibernate keze ügyében közelítse meg az entitáskezelőt egyszerű Java-val EntityManagerFactoryBuilderImpl osztály.

A JPA megvalósítás Java-val történő indításának részletes magyarázatát a cikkben találja.

3.4. A UserApplication Osztály

Végül refaktorozzuk a kezdőbetűt UserApplication osztályban, így működhet a JpaUserDao példány és CRUD műveleteket hajtson végre a Felhasználó entitások:

public class UserApplication {privát statikus Dao jpaUserDao; // standard konstruktorok public static void main (String [] args) {Felhasználói felhasználó1 = getUser (1); System.out.println (user1); updateUser (user1, új karakterlánc [] {"Jake", "[email protected]"}); saveUser (új felhasználó ("Monica", "[e-mail védett]")); deleteUser (getUser (2)); getAllUsers (). forEach (felhasználó -> System.out.println (user.getName ())); } public static User getUser (long id) {Opcionális user = jpaUserDao.get (id); return user.orElseGet (() -> new User ("nem létező felhasználó", "no-email")); } public static List getAllUsers () {return jpaUserDao.getAll (); } public static void updateUser (Felhasználó felhasználó, String [] paraméterek) {jpaUserDao.update (felhasználó, paraméterek); } public static void saveUser (Felhasználó felhasználó) {jpaUserDao.save (felhasználó); } public static void deleteUser (Felhasználó felhasználó) {jpaUserDao.delete (felhasználó); }}

Még akkor is, ha a példa valóban korlátozott, hasznos marad annak bemutatásához, hogy miként integrálható a DAO minta funkcionalitása az entitáskezelő által biztosított funkcióval.

A legtöbb alkalmazásban van egy DI keretrendszer, amely felelős a JpaUserDao például a UserApplication osztály. Az egyszerűség kedvéért kihagytuk ennek a folyamatnak a részleteit.

A stressz legrelevánsabb pontja itt a hogyan a JpaUserDao osztály segít megtartani a UserApplication osztály teljesen agnosztikus arról, hogy a perzisztencia réteg hogyan hajtja végre a CRUD műveleteket.

Ezenkívül felcserélhetjük a MySQL-t bármely más RDBMS-re (és akár egy sima adatbázisra) is tovább, és alkalmazásunk továbbra is a várt módon működne, köszönhetően a Dao interfész és az entitáskezelő.

4. Következtetés

Ebben a cikkben alaposan megvizsgáltuk a DAO minta kulcsfontosságú fogalmait, a Java-ban történő megvalósítását és a JPA entitáskezelőjén kívüli felhasználását.

Szokás szerint a cikkben bemutatott összes kódminta elérhető a GitHubon.