Tämän opetusohjelman alkupuoliskolla esiteltiin Java Persistence -sovellusliittymän perusteet ja näytettiin, kuinka voit määrittää JPA-sovelluksen horrostilan 5.3.6 ja Java 8: n avulla. Jos olet lukenut kyseisen opetusohjelman ja tutkinut sen esimerkkisovellusta, tiedät JPA-entiteettien ja monenvälisten suhteiden mallintaminen JPA: ssa. Sinulla on myös ollut jonkin verran käytäntöä nimettyjen kyselyiden kirjoittamiseen JPA Query Language (JPQL) -kielellä.
Tässä opetusohjelman toisessa puoliskossa menemme syvemmälle JPA: n ja horrostilan kanssa. Opit mallinnamaan monien ja monien välisen suhteen Elokuva
ja SuperHero
entiteetit, perustaa yksittäisiä arkistoja näille entiteeteille ja ylläpitää entiteettejä H2-muistitietokantaan. Opit myös enemmän kaskadioperaatioiden roolista JPA: ssa ja saat vinkkejä a CascadeType
strategia tietokannassa oleville yksiköille. Lopuksi kootaan yhteen toimiva sovellus, jonka voit suorittaa IDE: ssä tai komentorivillä.
Tämä opetusohjelma keskittyy JPA: n perusteisiin, mutta muista tarkistaa nämä Java-vinkit, joissa esitellään edistyneempiä aiheita JPA: ssa:
- Perintösuhteet JPA: ssa ja horrostilassa
- Yhdistetyt avaimet JPA: ssa ja horrostilassa
JPA: n monen ja monen väliset suhteet
Monista moniin-suhteet määritellä entiteetit, joiden suhteen molemmilla puolilla voi olla useita viittauksia toisiinsa. Esimerkkinä aiomme mallintaa elokuvia ja supersankareita. Toisin kuin osan 1 kirjoittajat ja kirjat, elokuvassa voi olla useita supersankareita, ja supersankari voi esiintyä useissa elokuvissa. Supersankarimme, Ironman ja Thor, esiintyvät molemmissa elokuvissa, "Kostajat" ja "Kostajat: Infinity War".
Tämän monien ja monien välisen suhteen mallintamiseksi JPA: lla tarvitaan kolme taulukkoa:
- ELOKUVA
- SUPER_HERO
- SUPERHERO_MOVIES
Kuvassa 1 on esitetty verkkotunnusmalli kolmen taulukon kanssa.
Steven HainesOta huomioon, että SuperHero_Movies
on liittyä pöydään välissä Elokuva
ja SuperHero
taulukoita. JPA: ssa liittymispöytä on erityinen pöytä, joka helpottaa monien ja monien välistä suhdetta.
Yksisuuntainen vai kaksisuuntainen?
JPA: ssa käytämme @ManyToMany
merkintä monien ja monien välisten suhteiden mallintamiseksi. Tämän tyyppinen suhde voi olla yksisuuntainen tai kaksisuuntainen:
- Jonkin sisällä yksisuuntainen suhde vain yksi suhteessa oleva yksikkö osoittaa toista.
- Jonkin sisällä kaksisuuntainen suhde molemmat entiteetit osoittavat toisiaan.
Esimerkkimme on kaksisuuntainen, eli elokuva osoittaa kaikkiin supersankareihinsa ja supersankari osoittaa kaikkiin heidän elokuviinsa. Kaksisuuntaisessa, monista moniin -suhteessa yksi kokonaisuus omistaa suhde ja toinen on kartoitettu suhde. Käytämme kartoitettu
attribuutti @ManyToMany
merkintä tämän kartoituksen luomiseksi.
Luettelossa 1 näkyy SuperHero
luokassa.
Listaus 1. SuperHero.java
paketti com.geekcap.javaworld.jpa.model; tuo javax.persistence.CascadeType; tuo javax.persistence.Entity; tuo javax.persistence.FetchType; tuo javax.persistence.GeneratedValue; tuo javax.persistence.Id; tuo javax.persistence.JoinColumn; tuo javax.persistence.JoinTable; tuo javax.persistence.ManyToMany; tuo javax.persistence.Table; tuo java.util.HashSet; tuo java.util.Set; tuoda java.util.stream.Collectors; @Entity @Table (name = "SUPER_HERO") julkisen luokan SuperHero {@Id @GeneratedValue private Integer id; yksityinen merkkijono nimi; @ManyToMany (fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) @JoinTable (name = "SuperHero_Movies", joinColumns = {@JoinColumn (name = "superhero_id")}, inverseJoinColumns = {@JoinColumn (name =) }) yksityisryhmäelokuvat = uusi HashSet (); public SuperHero () {} public SuperHero (Integer id, String name) {this.id = id; tämä.nimi = nimi; } public SuperHero (String name) {tämä.nimi = nimi; } public Integer getId () {return ID; } public void setId (kokonaisluku) {this.id = id; } public String getName () {palautusnimi; } public void setName (Merkkijonon nimi) {this.name = nimi; } public set getMovies () {paluuelokuvat; } @Override public String toString () {return "SuperHero {" + "id =" + id + ", + name +" \ '' + ", + movies.stream (). Map (Movie :: getTitle) .collect (Collectors.toList ()) + "\ '' + '}'; }}
SuperHero
luokassa on pari merkintää, joiden tulisi olla tuttuja osasta 1:
@Entity
tunnistaaSuperHero
JPA-kokonaisuutena.@Pöytä
kartoittaaSuperHero
"SUPER_HERO" -taulukkoon.
Huomaa myös Kokonaisluku
id
kenttä, joka määrittää, että taulukon ensisijainen avain luodaan automaattisesti.
Seuraavaksi tarkastelemme @ManyToMany
ja @JoinTable
merkinnät.
Strategioiden hakeminen
Asia, joka on huomioitava @ManyToMany
huomautus on miten konfiguroimme noutostrategia, joka voi olla laiska tai innokas. Tässä tapauksessa olemme asettaneet noutaa
että INNOKAS
, niin että kun haemme a SuperHero
tietokannasta haemme myös automaattisesti kaikki vastaavat Elokuva
s.
Jos päätämme suorittaa a LAISKA
sen sijaan haemme vain kukin Elokuva
koska sitä oli erityisesti käytetty. Laiska nouto on mahdollista vain SuperHero
on kiinnitetty EntityManager
; muuten supersankarin elokuvien katselu aiheuttaa poikkeuksen. Haluamme pystyä katsomaan supersankarin elokuvia pyynnöstä, joten tässä tapauksessa valitsemme INNOKAS
noutostrategia.
CascadeType.PERSIST
Cascade-toiminnot määritellä, miten supersankareita ja niitä vastaavia elokuvia säilytetään tietokannassa ja siitä. Valittavana on useita kaskadityyppisiä kokoonpanoja, joista puhumme myöhemmin tässä opetusohjelmassa. Toistaiseksi huomaa vain, että olemme asettaneet ryöpytä
attribuutti CascadeType.PERSIST
, mikä tarkoittaa, että kun tallennamme supersankarin, myös sen elokuvat tallennetaan.
Liity pöytiin
JoinTable
on luokka, joka helpottaa monien ja monien välistä suhdetta SuperHero
ja Elokuva
. Tässä luokassa määritellään taulukko, joka tallentaa molempien pääavaimet SuperHero
ja Elokuva
yhteisöt.
Listaus 1 määrittää, että taulukon nimi tulee olemaan SuperHero_Movies
. liity sarakkeeseen tulee olemaan supersankari_id
, ja käänteinen liitos sarake tulee olemaan movie_id
. SuperHero
entiteetti omistaa suhteen, joten liittymissarake täytetään SuperHero
ensisijainen avain. Käänteisliitos -sarakkeessa viitataan sitten entiteettiin suhteen toisella puolella, mikä on Elokuva
.
Näiden luettelon 1 määritelmien perusteella odotamme uuden taulukon luomista nimeltä SuperHero_Movies
. Taulukossa on kaksi saraketta: supersankari_id
, joka viittaa id
-sarakkeessa SUPERHERO
ja taulukko movie_id
, joka viittaa id
-sarakkeessa ELOKUVA
pöytä.
Elokuva-luokka
Luettelossa 2 näkyy Elokuva
luokassa. Muistakaamme, että kaksisuuntaisessa suhteessa yksi yksikkö omistaa suhteen (tässä tapauksessa SuperHero
), kun taas toinen on kartoitettu suhteeseen. Listing 2: n koodi sisältää Elokuva
luokassa.
Listaus 2. Movie.java
paketti com.geekcap.javaworld.jpa.model; tuo javax.persistence.CascadeType; tuo javax.persistence.Entity; tuo javax.persistence.FetchType; tuo javax.persistence.GeneratedValue; tuo javax.persistence.Id; tuo javax.persistence.ManyToMany; tuo javax.persistence.Table; tuo java.util.HashSet; tuo java.util.Set; @Entity @Table (name = "MOVIE") public class Movie {@Id @GeneratedValue private Integer id; yksityinen merkkijono; @ManyToMany (mappedBy = "elokuvat", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) yksityisjoukko superHeroes = uusi HashSet (); julkinen elokuva () {} julkinen elokuva (kokonaisluku, merkkijono) {this.id = id; this.title = otsikko; } julkinen elokuva (merkkijono) {this.title = title; } public Integer getId () {return ID; } public void setId (kokonaisluku) {this.id = id; } public String getTitle () {return title; } public void setTitle (Merkkijono) {this.title = title; } public set getSuperHeroes () {return superHeroes; } public void addSuperHero (SuperHero superHero) {superHeroes.add (superHero); superHero.getMovies (). lisää (tämä); } @Override public String toString () {return "Elokuva {" + "id =" + id + ", + title +" \ '' + '}'; }}
Seuraavia ominaisuuksia käytetään @ManyToMany
merkintä luettelossa 2:
kartoitettu
viittaa kentän nimeenSuperHero
luokka, joka hoitaa monia moniin-suhdetta. Tässä tapauksessa se viittaa elokuvia , jonka määrittelemme luettelossa 1 vastaavallaJoinTable
.ryöpytä
on määritettyCascadeType.PERSIST
, mikä tarkoittaa, että kun aElokuva
tallennetaan vastaavaSuperHero
myös yksiköt tulisi tallentaa.hae
kertooEntityManager
että sen pitäisi hakea elokuvan supersankareita innokkaasti: kun se latautuu aElokuva
, sen tulisi myös ladata kaikki vastaavatSuperHero
yhteisöt.
Jotain muuta huomattavaa Elokuva
luokka on sen addSuperHero ()
menetelmä.
Kun määrität entiteettejä pysyvyyttä varten, ei riitä, että supersankari lisätään yksinkertaisesti elokuvaan; meidän on myös päivitettävä suhteiden toinen puoli. Tämä tarkoittaa, että meidän on lisättävä elokuva supersankariin. Kun suhteen molemmat puolet on määritetty oikein, niin että elokuvassa on viittaus supersankariin ja supersankariin viittaus elokuvaan, myös liitostaulukko täytetään oikein.
Olemme määrittäneet kaksi yksikköämme. Tarkastellaan nyt arkistoja, joita käytämme niiden säilyttämiseen tietokantaan ja siitä.
Kärki! Aseta pöydän molemmat puolet
Se on yleinen virhe asettaa vain yksi puoli suhteesta, säilyttää entiteetti ja havaita sitten, että liittymispöytä on tyhjä. Suhteen molempien puolien asettaminen korjaa tämän.
JPA-arkistot
Voisimme toteuttaa kaiken pysyvyyskoodimme suoraan esimerkkisovelluksessa, mutta arkistoluokkien luominen antaa meille mahdollisuuden erottaa pysyvyyskoodi sovelluskoodista. Aivan kuten teimme osassa 1 olevan Kirjat ja kirjoittajat -sovelluksen kanssa, luomme EntityManager
ja käytä sitä sen jälkeen kahden alustuksen alustamiseen, yksi kutakin jatkuvaa yksikköä varten.
Luettelossa 3 näkyy MovieRepository
luokassa.
Listaus 3. MovieRepository.java
paketti com.geekcap.javaworld.jpa.repository; tuo com.geekcap.javaworld.jpa.model.Elokuva; tuo javax.persistence.EntityManager; tuo java.util.List; tuo java.util.Valinnainen; julkinen luokka MovieRepository {private EntityManager entityManager; public MovieRepository (EntityManager entityManager) {this.entityManager = entitManager; } julkinen Valinnainen tallennus (elokuva) {kokeile {entityManager.getTransaction (). begin (); entitManager.persist (elokuva); entityManager.getTransaction (). sitoutu (); return Valinnainen (elokuva); } catch (Poikkeus e) {e.printStackTrace (); } return Valinnainen. tyhjä (); } public Valinnainen findById (Kokonaisluku) {Elokuvaelokuva = entitManager.find (Elokuva.luokka, id); palaa elokuvaan! = null? Valinnainen. (Elokuva): Valinnainen. Tyhjä (); } public list findAll () {return entityManager.createQuery ("from Movie"). getResultList (); } public void deleteById (Kokonaisluku) {// Nouda elokuva tällä tunnuksella Elokuva elokuva = entitManager.find (Elokuva.luokka, id); if (elokuva! = null) {yritä {// Aloita tapahtuma, koska muutamme tietokannan entiteettiäManager.getTransaction (). begin (); // Poista kaikki viittaukset tähän elokuvaan supersankareiden kautta movie.getSuperHeroes (). ForEach (superHero -> {superHero.getMovies (). Remove (movie);}); // Poista nyt elokuvayksikköManager.remove (movie); // Suorita tapahtuman entiteettiManager.getTransaction (). Sitoutu (); } catch (Poikkeus e) {e.printStackTrace (); }}}}
MovieRepository
on alustettu EntityManager
, sitten tallentaa sen jäsenmuuttujaan käytettäväksi sen pysyvyysmenetelmissä. Harkitsemme kaikkia näitä menetelmiä.
Pysyvyysmenetelmät
Tarkastellaan MovieRepository
n pysyvyysmenetelmiä ja miten ne ovat vuorovaikutuksessa EntityManager
sinnikkyysmenetelmät.