Šīs apmācības pirmajā pusē tika ievadīti Java Noturības API pamati un parādīts, kā konfigurēt JPA lietojumprogrammu, izmantojot hibernācijas 5.3.6 un Java 8. Ja esat izlasījis šo apmācību un izpētījis tās piemēru, tad jūs zināt JPA entītiju un daudzu savstarpējo attiecību modelēšana JPA. Jums ir bijusi arī prakse rakstīt nosauktus vaicājumus ar JPA vaicājumu valodu (JPQL).
Šajā apmācības otrajā pusē mēs iedziļināsimies JPA un hibernācijas režīmā. Jūs uzzināsiet, kā modelēt attiecības starp daudziem pret daudziem Filma
un SuperHero
entītijām, izveidojiet šīm entītijām atsevišķus krātuves un saglabājiet entītijas H2 atmiņas datu bāzē. Jūs arī uzzināsiet vairāk par kaskādes darbību nozīmi JPA un saņemsiet padomus a CascadeType
stratēģija datu bāzē esošajām vienībām. Visbeidzot, mēs apkoposim darbojošos lietojumprogrammu, kuru varat palaist IDE vai komandrindā.
Šajā apmācībā galvenā uzmanība tiek pievērsta JPA pamatiem, taču noteikti pārbaudiet šos Java padomus, ieviešot progresīvākas tēmas JPA:
- Mantojuma attiecības JPA un hibernātā
- Saliktie taustiņi JPA un hibernācijas režīmā
Daudzas pret daudziem attiecības JPA
Daudzas pret daudzām attiecības definējiet entītijas, kurām abām attiecību pusēm var būt vairākas atsauces uz otru. Piemēram, mēs veidosim filmas un supervaroņus. Atšķirībā no autoru un grāmatu 1. daļas piemēra, filmai var būt vairāki supervaroņi, un supervaronis var parādīties vairākās filmās. Mūsu supervaroņi - Ironman un Thor - abi parādās divās filmās: "The Avengers" un "Avengers: Infinity War".
Lai modelētu šīs attiecības pret daudziem, izmantojot JPA, mums būs nepieciešamas trīs tabulas:
- FILMA
- SUPER_HERO
- SUPERHERO_MOVIES
1. attēlā parādīts domēna modelis ar trim tabulām.
Stīvens HeinssPieraksti to SuperHero_Filmas
ir pievienoties galdam starp Filma
un SuperHero
tabulas. Apvienotajā parlamentārajā asamblejā pievienošanās galds ir īpaša veida galds, kas atvieglo attiecības starp daudziem pret daudziem.
Vienvirziena vai divvirzienu?
JPA mēs izmantojam @ManyToMany
anotācija, lai modelētu attiecības starp daudziem. Šāda veida attiecības var būt vienvirziena vai divvirzienu:
- Iekšā vienvirziena attiecības tikai viena attiecībās esoša vienība norāda otru.
- Iekšā divvirzienu attiecības abas entītijas norāda viena uz otru.
Mūsu piemērs ir divvirzienu, tas nozīmē, ka filma norāda uz visiem tās varoņiem un supervaronis norāda uz visām viņu filmām. Divvirzienu attiecībās “viens pret daudziem” viens subjekts pieder attiecības un otra ir kartēts ar attiecibas. Mēs izmantojam kartētsPēc
atribūts @ManyToMany
anotācija, lai izveidotu šo kartēšanu.
1. sarakstā ir redzams programmas avota kods SuperHero
klasē.
Sarakstā 1. SuperHero.java
pakete com.geekcap.javaworld.jpa.model; importēt javax.persistence.CascadeType; importēt javax.persistence.Entity; importēt javax.persistence.FetchType; importēt javax.persistence.GeneratedValue; importēt javax.persistence.Id; importēt javax.persistence.JoinColumn; importēt javax.persistence.JoinTable; importēt javax.persistence.ManyToMany; importēt javax.persistence.Table; importēt java.util.HashSet; importēt java.util.Set; importēt java.util.stream.Collectors; @Entity @Table (name = "SUPER_HERO") publiskās klases supervaronis {@Id @GeneratedValue private Integer id; privāts virknes nosaukums; @ManyToMany (fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) @JoinTable (name = "SuperHero_Movies", joinColumns = {@JoinColumn (name = "superhero_id")}}, inverseJoinColumns = {@JoinColumn (name = }) private Set movies = new HashSet (); public SuperHero () {} public SuperHero (Integer id, String name) {this.id = id; this.name = nosaukums; } publiskais supervaronis (virknes nosaukums) {this.name = name; } public Integer getId () {return ID; } public void setId (Integer id) {this.id = id; } public String getName () {atgriešanās nosaukums; } public void setName (virknes nosaukums) {this.name = name; } public Set getMovies () {atgriešanās filmas; } @Orride public String toString () {return "SuperHero {" + "id =" + id + ", + name +" \ '' + ", + movies.stream (). Map (Movie :: getTitle) .collect (Collectors.toList ()) + "\ '' + '}'; }}
The SuperHero
klasē ir pāris anotācijas, kurām vajadzētu būt pazīstamām no 1. daļas:
@Entity
identificēSuperHero
kā APA vienība.@Tabula
kartēSuperHero
entītiju tabulā "SUPER_HERO".
Ņemiet vērā arī Vesels skaitlis
id
lauks, kas norāda, ka tabulas galvenā atslēga tiks automātiski ģenerēta.
Tālāk mēs apskatīsim @ManyToMany
un @JoinTable
anotācijas.
Stratēģiju ienešana
Lieta, ko pamanīt @ManyToMany
anotācija ir tā, kā mēs konfigurējam ienesšanas stratēģija, kas var būt slinks vai vēlas. Šajā gadījumā mēs esam iestatījuši atnest
uz VĒLĒTĀJS
, tā, ka tad, kad mēs iegūstam a SuperHero
no datu bāzes mēs arī automātiski izgūsim visu atbilstošo Filma
s.
Ja mēs izvēlētos izpildīt a Slinkums
atnest, mēs tikai izgūtu katru Filma
jo tas bija īpaši pieejams. Slinki ielādēt ir iespējams tikai tad, kad SuperHero
ir pievienots EntityManager
; pretējā gadījumā piekļuve supervaroņa filmām radīs izņēmumu. Mēs vēlamies, lai pēc pieprasījuma varētu piekļūt supervaroņa filmām, tāpēc šajā gadījumā mēs izvēlamies VĒLĒTĀJS
ienesšanas stratēģija.
CascadeType.PERSIST
Kaskādes operācijas definējiet, kā supervaroņi un viņu filmas tiek saglabāti datu bāzē un no tās. Ir vairākas kaskādes tipa konfigurācijas, no kurām izvēlēties, un par tām mēs vairāk runāsim vēlāk šajā apmācībā. Pagaidām vienkārši ņemiet vērā, ka esam iestatījuši kaskāde
atribūts CascadeType.PERSIST
, kas nozīmē, ka, saglabājot supervaroni, tiks saglabātas arī tā filmas.
Pievienojieties galdiem
JoinTable
ir klase, kas atvieglo attiecības starp daudziem pret daudziem SuperHero
un Filma
. Šajā klasē mēs definējam tabulu, kurā tiks glabātas abas galvenās atslēgas SuperHero
un Filma
vienības.
1. saraksts norāda, ka tabulas nosaukums būs SuperHero_Filmas
. The pievienoties kolonnai būs superhero_id
un apgrieztā savienojuma kolonna būs movie_id
. The SuperHero
vienībai pieder attiecības, tāpēc kolonnā Pievienoties tiks aizpildīta SuperHero
galvenā atslēga. Kolonnā Apgrieztā pievienošanās tiek norādīts uz entītiju attiecību otrā pusē, kas ir Filma
.
Pamatojoties uz šīm 1. saraksta definīcijām, mēs sagaidām, ka tiks izveidota jauna tabula ar nosaukumu SuperHero_Filmas
. Tabulā būs divas kolonnas: superhero_id
, kas atsaucas uz id
kolonna SUPERHERO
tabula un movie_id
, kas atsaucas uz id
kolonna FILMA
tabula.
Filmu klase
2. Sarakstā ir redzams Filma
klasē. Atgādināsim, ka divvirzienu attiecībās attiecības pieder vienai vienībai (šajā gadījumā SuperHero
), kamēr otrs ir attēlots attiecībās. Kods 2 sarakstā ietver attiecību kartēšanu, kas tiek piemērota Filma
klasē.
Saraksts 2. Movie.java
pakete com.geekcap.javaworld.jpa.model; importēt javax.persistence.CascadeType; importēt javax.persistence.Entity; importēt javax.persistence.FetchType; importēt javax.persistence.GeneratedValue; importēt javax.persistence.Id; importēt javax.persistence.ManyToMany; importēt javax.persistence.Table; importēt java.util.HashSet; importēt java.util.Set; @Entity @Table (name = "MOVIE") public class Movie {@Id @GeneratedValue private Integer id; privāts stīgu nosaukums; @ManyToMany (mappedBy = "filmas", kaskāde = CascadeType.PERSIST, fetch = FetchType.EAGER) privāts Set superHeroes = jauns HashSet (); publiskā filma () {} publiskā filma (vesels skaitlis, virknes nosaukums) {this.id = id; this.title = nosaukums; } publiskā filma (virknes nosaukums) {this.title = title; } public Integer getId () {return ID; } public void setId (Integer id) {this.id = id; } public String getTitle () {atgriešanās nosaukums; } public void setTitle (virknes nosaukums) {this.title = nosaukums; } public set getSuperHeroes () {return superHeroes; } public void addSuperHero (SuperHero superHero) {superHeroes.add (superHero); superHero.getMovies (). pievienot (šo); } @Orride public String toString () {return "Filma {" + "id =" + id + ", + title +" \ '' + '}'; }}
Šim īpašumam tiek izmantotas šādas īpašības @ManyToMany
anotācija 2. sarakstā:
kartētsPēc
atsauces uz lauka nosaukumu uzSuperHero
klase, kas pārvalda attiecības pret daudziem. Šajā gadījumā tas atsaucas uz filmas lauks, kuru mēs definējām 1. sarakstā ar atbilstošoJoinTable
.kaskāde
ir konfigurētsCascadeType.PERSIST
, kas nozīmē, ka tad, kad aFilma
tiek saglabāts atbilstošaisSuperHero
būtu jāsaglabā arī vienības.atnest
stāstaEntityManager
ka tai būtu jāatgūst filmas supervaroņi dedzīgi: kad tas ielādējas aFilma
, tam vajadzētu ielādēt arī visus atbilstošosSuperHero
vienības.
Kaut kas cits, kas jāatzīmē par Filma
klase ir tā addSuperHero ()
metodi.
Konfigurējot entītijas noturībai, nepietiek tikai ar supervaroņa pievienošanu filmai; mums jāatjaunina arī otra attiecību puse. Tas nozīmē, ka mums filma jāpievieno supervaronim. Kad abas attiecību puses ir pareizi konfigurētas tā, ka filmai ir atsauce uz supervaroni un supervaronim ir atsauce uz filmu, tad arī pievienošanās tabula būs pareizi aizpildīta.
Mēs esam definējuši abas savas entītijas. Tagad apskatīsim krātuves, kuras izmantosim, lai tās saglabātu datu bāzē un no tās.
Padoms! Uzstādiet abas galda puses
Bieža kļūda ir iestatīt tikai vienu attiecību pusi, saglabāt entītiju un pēc tam novērot, ka pievienošanās tabula ir tukša. Nosakot abas attiecību puses, tas tiks novērsts.
JPA krātuves
Mēs varētu ieviest visu mūsu noturības kodu tieši lietojumprogrammas paraugā, taču, izveidojot repozitorija klases, mēs varam nodalīt noturības kodu no lietojumprogrammas koda. Tāpat kā mēs to darījām ar grāmatu un autoru lietojumprogrammu 1. daļā, mēs izveidosim EntityManager
un pēc tam izmantojiet to, lai inicializētu divus krātuves, vienu katrai entītijai, kuru mēs pastāvam.
3. sarakstā ir redzams MovieRepository
klasē.
Saraksts 3. MovieRepository.java
pakete com.geekcap.javaworld.jpa.repository; importēt com.geekcap.javaworld.jpa.model.Filma; importēt javax.persistence.EntityManager; importēt java.util.List; importēt java.util.Papildu; publiskā klase MovieRepository {private EntityManager entityManager; public MovieRepository (EntityManager entityManager) {this.entityManager = entityManager; } public Izvēles izvēles saglabāšana (Filmas filma) {mēģiniet {entityManager.getTransaction (). sākt (); entityManager.persist (filma); entityManager.getTransaction (). izdarīt (); atgriezties pēc izvēles (filma); } catch (izņēmums e) {e.printStackTrace (); } atgriešanās Optional.empty (); } public Izvēles findById (Integer id) {Movie movie = entityManager.find (Movie.class, id); atgriešanās filma! = null? Neobligāts (filmai): Neobligāti. Tukšs (); } public List findAll () {return entityManager.createQuery ("from Movie"). getResultList (); } public void deleteById (Integer id) {// Ielādēt filmu ar šo ID Movie movie = entityManager.find (Movie.class, id); if (filma! = null) {mēģiniet {// Sākt darījumu, jo mēs mainīsim datu bāzes entītijuManager.getTransaction (). begin (); // Noņemiet visas supervaroņu atsauces uz šo filmu movie.getSuperHeroes (). ForEach (superHero -> {superHero.getMovies (). Noņemt (filma);}); // Tagad noņemiet filmas entītijuManager.remove (movie); // Izpildiet darījuma entītijuManager.getTransaction (). Saistības (); } catch (izņēmums e) {e.printStackTrace (); }}}}
The MovieRepository
tiek inicializēts ar EntityManager
, tad to saglabā dalībnieka mainīgajā, lai izmantotu tā noturības metodēs. Mēs apsvērsim katru no šīm metodēm.
Noturības metodes
Pārskatīsim MovieRepository
un noturības metodes un redzēt, kā tās mijiedarbojas ar EntityManager
noturības metodes.