DAO obrazac u Javi

1. Pregled

Uzorak objekta pristupa podacima (DAO) strukturni je obrazac koji nam to omogućuje izolirati aplikacijski / poslovni sloj od sloja postojanosti (obično relacijske baze podataka, ali to može biti bilo koji drugi mehanizam postojanosti) pomoću apstraktnog API-ja.

Funkcionalnost ovog API-ja je skrivanje od aplikacije svih složenosti uključenih u izvođenje CRUD operacija u osnovnom mehanizmu za pohranu. To omogućuje da se oba sloja razvijaju odvojeno, a da ništa ne znaju jedni o drugima.

U ovom ćemo uputstvu duboko zaroniti u implementaciju uzorka i naučit ćemo kako ga koristiti za apstrahiranje poziva upravitelju JPA entiteta.

2. Jednostavna provedba

Da bismo razumjeli kako funkcionira DAO obrazac, stvorimo osnovni primjer.

Recimo da želimo razviti aplikaciju koja upravlja korisnicima. Stvorit ćemo kako bi model domene aplikacije bio potpuno agnostičan u vezi s bazom podataka jednostavna DAO klasa koja će se pobrinuti da ove komponente budu uredno odvojene jedna od druge.

2.1. Razred domene

Kako će naša aplikacija raditi s korisnicima, moramo definirati samo jednu klasu za implementaciju modela domene:

korisnik javne klase {naziv privatnog niza; privatni String e-mail; // konstruktori / standardni postavljači / getteri}

The Korisnik class je samo obični spremnik za korisničke podatke, tako da ne provodi bilo koje drugo ponašanje vrijedno naglaska.

Naravno, najrelevantniji izbor dizajna koji ovdje trebamo napraviti je kako zadržati aplikaciju koja koristi ovu klasu izoliranu od bilo kojeg mehanizma postojanosti koji bi se u nekom trenutku mogao implementirati.

Pa, upravo je to problem koji DAO obrazac pokušava riješiti.

2.2. DAO API

Definirajmo osnovni DAO sloj, kako bismo mogli vidjeti kako to može držati model domene potpuno odvojenim od sloja postojanosti.

Evo DAO API-ja:

javno sučelje Dao {Neobvezno get (long id); Popis getAll (); spremanje praznine (T t); ažuriranje praznine (T t, Parametri niza []); brisanje praznine (T t); }

Iz ptičje perspektive jasno je vidjeti da Dao sučelje definira apstraktni API koji izvodi CRUD operacije na objektima tipa T.

Zbog visoke razine apstrakcije koju sučelje pruža, lako je stvoriti konkretnu, finozrnatu implementaciju koja radi s Korisnik predmeta.

2.3. The UserDao Razred

Definirajmo korisničku implementaciju Dao sučelje:

javna klasa UserDao implementira Dao {private list users = new ArrayList (); javni UserDao () {users.add (novi korisnik ("John", "[e-pošta zaštićena]")); users.add (novi korisnik ("Susan", "[e-pošta zaštićena]")); } @Override public Neobavezno get (long id) {return Optional.ofNullable (users.get ((int) id)); } @Override javni popis getAll () {povratak korisnika; } @Override public void save (Korisnik korisnik) {users.add (korisnik); } @Override javno void ažuriranje (User user, String [] params) {user.setName (Objects.requireNonNull (params [0], "Ime ne može biti null")); user.setEmail (Objects.requireNonNull (params [1], "E-adresa ne može biti null")); users.add (korisnik); } @Override public void delete (Korisnik korisnik) {users.remove (korisnik); }}

The UserDao klasa implementira svu funkcionalnost potrebnu za dohvaćanje, ažuriranje i uklanjanje Korisnik predmeta.

Radi jednostavnosti, Popis korisnika djeluje poput baze podataka u memoriji, koja je popunjena s nekoliko Korisnik objekti u konstruktoru.

Naravno, lako je refaktorizirati ostale metode, tako da mogu raditi, na primjer, s relacijskom bazom podataka.

Dok su oba Korisnik i UserDao klase koegzistiraju neovisno unutar iste aplikacije, još trebamo vidjeti kako se potonji mogu koristiti za čuvanje sloja postojanosti skrivenog od logike aplikacije:

javna klasa UserApplication {private static Dao userDao; javna statička void glavna (String [] args) {userDao = novi UserDao (); Korisnik user1 = getUser (0); System.out.println (korisnik1); userDao.update (user1, novi String [] {"Jake", "[email protected]"}); Korisnik user2 = getUser (1); userDao.delete (user2); userDao.save (novi korisnik ("Julie", "[e-pošta zaštićena]")); userDao.getAll (). forEach (korisnik -> System.out.println (user.getName ())); } privatni statički korisnik getUser (dugi id) {Izborni korisnik = userDao.get (id); vratiti user.orElseGet (() -> novi korisnik ("nepostojeći korisnik", "bez e-pošte")); }}

Primjer je izmišljen, ali ukratko pokazuje motivaciju za DAO uzorkom. U ovom slučaju, glavni metoda samo koristi a UserDao instance za izvođenje CRUD operacija na nekolicini Korisnik predmeta.

Najvažniji aspekt ovog postupka je kako UserDao skriva od aplikacije sve detalje niske razine o tome kako se objekti održavaju, ažuriraju i brišu.

3. Korištenje uzorka s JPA

Općenito postoji tendencija među programerima da misle kako je izdanje JPA svedeno na nulu funkcionalnost DAO uzorka, jer uzorak postaje samo još jedan sloj apstrakcije i složenosti implementiran povrh onog koji pruža upravitelj entiteta JPA.

Nedvojbeno, u nekim scenarijima to je istina. Čak i tako, ponekad samo želimo izložiti našoj aplikaciji samo nekoliko metoda specifičnih za domenu API-ja upravitelja entiteta. U takvim slučajevima DAO obrazac ima svoje mjesto.

3.1. The JpaUserDao Razred

Uz to, kreirajmo novu implementaciju Dao sučelje, tako da možemo vidjeti kako može uklopiti funkcionalnost koju JPA-ov upravitelj entiteta nudi izravno:

javna klasa JpaUserDao implementira Dao {private EntityManager entityManager; // standardni konstruktori @Override public Izborni get (long id) {return Optional.ofNullable (entityManager.find (User.class, id)); } @Override javni popis getAll () {Query query = entityManager.createQuery ("SELECT e FROM User e"); vratiti query.getResultList (); } @Override public void save (User user) {executeInsideTransaction (entityManager -> entityManager.persist (user)); } @Override javno void ažuriranje (User user, String [] params) {user.setName (Objects.requireNonNull (params [0], "Ime ne može biti null")); user.setEmail (Objects.requireNonNull (params [1], "E-adresa ne može biti null")); executeInsideTransaction (entityManager -> entityManager.merge (korisnik)); } @Override public void delete (Korisnik korisnik) {executeInsideTransaction (entityManager -> entityManager.remove (user)); } private void executeInsideTransaction (Potrošačka radnja) {EntityTransaction tx = entityManager.getTransaction (); isprobajte {tx.begin (); action.accept (entityManager); tx.commit (); } catch (RuntimeException e) {tx.rollback (); baciti e; }}}

The JpaUserDao klasa je sposobna za rad s bilo kojom relacijskom bazom podataka koju podržava implementacija JPA.

Nadalje, ako pažljivo pogledamo klasu, shvatit ćemo kako nam upotreba ubrizgavanja sastava i ovisnosti omogućuje pozivanje samo metoda upravitelja entiteta koje zahtijeva naša aplikacija.

Jednostavno rečeno, imamo API prilagođen domeni, a ne cijeli API upravitelja entiteta.

3.2. Refaktoriziranje Korisnik Razred

U ovom ćemo slučaju koristiti Hibernate kao zadanu implementaciju JPA, pa ćemo refaktorizirati Korisnik klasa u skladu s tim:

@Entity @Table (name = "users") javna klasa Korisnik {@Id @GeneratedValue (strategy = GenerationType.AUTO) private long id; privatni naziv niza; privatni String e-mail; // standardni konstruktori / postavljači / getteri}

3.3. Podizanje sustava JPA Entity Manager Programski

Pod pretpostavkom da već imamo radnu instancu MySQL-a koja se izvodi lokalno ili udaljeno i tablicu baze podataka "Korisnici" popunjen nekim korisničkim zapisima, moramo dobiti upravitelja entiteta JPA, kako bismo mogli koristiti JpaUserDao klasa za izvođenje CRUD operacija u bazi podataka.

U većini slučajeva to postižemo tipičnim "Persistence.xml" datoteku, što je standardni pristup.

U ovom ćemo slučaju uzeti "Bez xml" pristupite i vodite entiteta s običnom Javom kroz Hibernate-ov priručnik EntityManagerFactoryBuilderImpl razred.

Detaljno objašnjenje o pokretanju JPA implementacije s Javom potražite u ovom članku.

3.4. The Aplikacija korisnika Razred

Napokon, refaktoriziramo početno slovo Aplikacija korisnika razreda, tako da može raditi s a JpaUserDao instancu i izvršiti CRUD operacije na Korisnik entiteti:

javna klasa UserApplication {private static Dao jpaUserDao; // standardni konstruktori public static void main (String [] args) {User user1 = getUser (1); System.out.println (korisnik1); updateUser (user1, novi String [] {"Jake", "[email protected]"}); saveUser (novi korisnik ("Monica", "[e-pošta zaštićena]")); deleteUser (getUser (2)); getAllUsers (). forEach (korisnik -> System.out.println (user.getName ())); } javni statični korisnik getUser (dugi id) {Izborni korisnik = jpaUserDao.get (id); vratiti user.orElseGet (() -> novi korisnik ("nepostojeći korisnik", "bez e-pošte")); } javni statički popis getAllUsers () {return jpaUserDao.getAll (); } javna statička praznina updateUser (Korisnik, parametar String []) {jpaUserDao.update (korisnik, parametar); } javna statička praznina saveUser (korisnik korisnika) {jpaUserDao.save (korisnik); } javna statička praznina deleteUser (korisnik korisnika) {jpaUserDao.delete (korisnik); }}

Čak i kada je primjer uistinu prilično ograničen, i dalje ostaje koristan za pokazivanje kako integrirati funkcionalnost DAO uzorka s onom koju pruža upravitelj entiteta.

U većini aplikacija postoji DI okvir koji je odgovoran za ubrizgavanje a JpaUserDao primjer u Aplikacija korisnika razred. Radi jednostavnosti, izostavili smo detalje ovog postupka.

Ovdje je najvažnije naglasiti kako the JpaUserDao razred pomaže zadržati Aplikacija korisnika razred potpuno agnostički o tome kako postojani sloj izvodi CRUD operacije.

Uz to, MySQL bismo mogli zamijeniti za bilo koji drugi RDBMS (pa čak i za ravnu bazu podataka) dalje na putu, a opet, naša bi aplikacija nastavila raditi prema očekivanjima, zahvaljujući razini apstrakcije koju pruža Dao sučelje i upravitelj entiteta.

4. Zaključak

U ovom smo članku detaljno pogledali ključne koncepte DAO uzorka, kako ga implementirati u Javu i kako ga koristiti povrh upravitelja entiteta JPA.

Kao i obično, svi uzorci koda prikazani u ovom članku dostupni su na GitHubu.