Výukový program pre hibernáciu jednej z mnohých poznámok

1. Úvod

Tento rýchly výukový program Hibernate nás prevedie príkladom a jedna k mnohým mapovanie pomocou anotácií JPA, alternatíva k XML.

Dozvieme sa tiež, čo sú obojsmerné vzťahy, ako môžu vytvárať nezrovnalosti a ako môže pomôcť myšlienka vlastníctva.

2. Opis

Jednoducho povedané,jedna k mnohým mapovanie znamená, že jeden riadok v tabuľke je namapovaný na viac riadkov v inej tabuľke.

Pozrime sa na nasledujúci diagram vzťahov entít, aby sme videli a jedna k mnohým združenie:

V tomto príklade implementujeme systém košíkov, kde máme tabuľku pre každý košík a ďalšiu tabuľku pre každú položku. Jeden košík môže obsahovať veľa položiek, takže tu máme jedna k mnohým mapovanie.

Na úrovni databázy to funguje tak, že máme a cart_id ako primárny kľúč v vozík stôl a tiež a cart_id ako cudzí kľúč v položky.

V kóde to robíme takto @OneToMany.

Poďme zmapovať Košík triedy do Položky objekt spôsobom, ktorý odráža vzťah v databáze:

public class Cart {// ... @OneToMany (mappedBy = "cart") súkromné ​​položky sady; // ...}

Môžeme tiež pridať odkaz na Košík v Položky použitím @ManyToOne, čo z neho robí obojsmerný vzťah. Obousmerný to znamená máme prístup položky od vozíky, a tiež vozíky od položky.

The mappedBy property je to, čo používame na to, aby sme Hibernate povedali, ktorú premennú používame na reprezentáciu rodičovskej triedy v našej podradenej triede.

Nasledujúce technológie a knižnice sa používajú na vývoj vzorovej aplikácie Hibernate, ktorá sa implementuje jedna k mnohým združenie:

  • JDK 1,8 alebo novší
  • Hibernácia 5
  • Maven 3 alebo novší
  • Databáza H2

3. Inštalácia

3.1. Nastavenie databázy

Nižšie je uvedený náš databázový skript pre Košík a Položky stoly. Používame obmedzenie cudzieho kľúča pre jedna k mnohým mapovanie:

CREATE TABLE `Cart` (` cart_id` int (11) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`cart_id`)) ENGINE = InnoDB AUTO_INCREMENT = 5 DEFAULT CHARSET = utf8; CREATE TABLE `Items` (` id` int (11) unsigned NOT NULL AUTO_INCREMENT, `cart_id` int (11) unsigned NOT NULL, PRIMARY KEY (` id`), KEY `cart_id` (` cart_id`), CONSTRAINT `items_ibfk_1 `ZAHRANIČNÝ KLÍČ (` cart_id`) REFERENCIE `Cart` (` cart_id`)) ENGINE = InnoDB AUTO_INCREMENT = 7 VÝCHOZÍ CHARSET = utf8;

Naše nastavenie databázy je pripravené, takže poďme k vytvoreniu ukážkového projektu dlhodobého spánku.

3.2. Maven závislosti

Potom do nášho systému pridáme závislosti ovládačov Hibernate a H2 pom.xml spis. Závislosť režimu dlhodobého spánku používa protokolovanie JBoss a automaticky sa pridáva ako prechodné závislosti:

  • Hibernácia verzie 5.2.7. Konečné
  • Ovládač H2 verzia 1.4.197

Najnovšie verzie Hibernate a závislostí H2 nájdete v centrálnom úložisku Maven.

3.3. Konfigurácia dlhodobého spánku

Tu je konfigurácia režimu dlhodobého spánku:

  org.h2.Driver jdbc: h2: mem: spring_hibernate_one_to_many sa org.hibernate.dialect.H2Dialect vlákno true 

3.4. HibernateAnnotationUtil Trieda

Vďaka HibernateAnnotationUtil triedy, stačí odkázať na nový konfiguračný súbor režimu dlhodobého spánku:

private static SessionFactory sessionFactory; private SessionFactory buildSessionFactory () {ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder (). configure ("hibernate-annotation.cfg.xml"). build (); Metadata metadata = new MetadataSources (serviceRegistry) .getMetadataBuilder (). Build (); SessionFactory sessionFactory = metadata.getSessionFactoryBuilder (). Build (); návrat sessionFactory; } public SessionFactory getSessionFactory () {if (sessionFactory == null) sessionFactory = buildSessionFactory (); návrat sessionFactory; }

4. Modely

Konfigurácie súvisiace s mapovaním sa uskutočnia pomocou anotácií JPA v modelových triedach:

@Entity @Table (name = "CART") verejná trieda Cart {// ... @OneToMany (mappedBy = "cart") súkromné ​​položky sady; // zakladatelia a zakladatelia}

Upozorňujeme, že @OneToMany anotácia sa používa na definovanie vlastnosti v Položky triedy, ktorá sa použije na mapovanie mappedBy premenná. Preto máme nehnuteľnosť s názvom „vozík“V Položky trieda:

@Entity @Table (name = "ITEMS") položky verejnej triedy {// ... @ManyToOne @JoinColumn (name = "cart_id", nullable = false) súkromný košík; public Items () {} // getters and setters} 

Je tiež dôležité poznamenať, že @ManyToOne anotácia je spojená s Košík premenná triedy. @JoinColumn anotácia odkazuje na mapovaný stĺpec.

5. V akcii

V testovacom programe vytvárame triedu s a hlavný() metóda na získanie relácie dlhodobého spánku a uloženie modelových objektov do databázy implementujúcej jedna k mnohým združenie:

sessionFactory = HibernateAnnotationUtil.getSessionFactory (); session = sessionFactory.getCurrentSession (); System.out.println ("Relácia vytvorená"); tx = session.beginTransaction (); session.save (košík); session.save (položka1); session.save (item2); tx.commit (); System.out.println ("Cartitem1, cudzí kľúč Cartitem2, cudzí kľúč Cartmany-to-one">6. @ManyToOne Anotácia

Ako sme videli v časti 2, môžeme určiť a mnoho-k-jednému vzťah pomocou @ManyToOne anotácia. A mnoho-k-jednému mapovanie znamená, že veľa inštancií tejto entity je mapovaných na jednu inštanciu inej entity - veľa položiek v jednom košíku.

The @ManyToOne anotácia nám umožňuje vytvárať aj obojsmerné vzťahy. Tomu sa budeme podrobne venovať v niekoľkých nasledujúcich pododdieloch.

6.1. Nezrovnalosti a vlastníctvo

Teraz, ak Košík odkazované Položky, ale Položky nemal zase odkaz Košík, náš vzťah by bol jednosmerný. Predmety by mali tiež prirodzenú konzistenciu.

V našom prípade je však vzťah obojsmerný, zavedenie možnosti nekonzistencie.

Poďme si predstaviť situáciu, keď chce vývojár pridať položka1 do vozík a položka2 do košík2, ale robí chybu tak, že odkazy medzi košík2 a položka2 sa stanú nekonzistentnými:

Cart cart1 = nový košík (); Cart cart2 = nový košík (); Položky item1 = nové položky (cart1); Položky item2 = nové položky (cart2); Set itemsSet = new HashSet (); itemsSet.add (item1); itemsSet.add (item2); cart1.setItems (itemsSet); // zle!

Ako je uvedené vyššie, položka2 referencie cart2, keďže košík2 neodkazuje item2, a to je zlé.

Ako by mal režim dlhodobého spánku šetriť položka2 do databázy? Will položka2 odkaz na cudzí kľúč košík1 alebo košík2?

Túto nejednoznačnosť riešime pomocou myšlienky vlastniť stranu vzťahu; odkazy patriace vlastniacej strane majú prednosť a ukladajú sa do databázy.

6.2. Položky ako strana vlastniaca

Ako je uvedené v špecifikácii JPA v časti 2.9, je dobrým zvykom známkovať mnoho-k-jednému strana ako strana vlastniaca.

Inými slovami, Jatems by bola vlastniacou stranou a Košík inverzná strana, čo je presne to, čo sme urobili predtým.

Ako sme to teda dosiahli?

Zahrnutím mappedBy atribút v Košík triedy, označíme ako inverznú stranu.

Zároveň tiež anotujeme Položky.vozík pole s @ManyToOne, výroba Položky vlastniaca strana.

Keď sa vrátime k nášmu príkladu „nekonzistencie“, Hibernate teraz vie, že položka2Odkaz je dôležitejší a ušetrí položka2Odkaz na databázu.

Poďme skontrolovať výsledok:

item1 ID = 1, ID košíka s cudzím kľúčom = 1 item2 ID = 2, ID košíka s cudzím kľúčom = 2

Hoci vozík referencie položka2 v našom úryvku, položka2Odkaz na košík2 je uložený v databáze.

6.3. Košík ako strana vlastniaca

Je tiež možné označiť jedna k mnohým strana ako strana vlastniaca a - mnoho-k-jednému strana ako inverzná strana.

Aj keď to nie je odporúčaná prax, poďme to skúsiť.

Fragment kódu nižšie ukazuje implementáciu jedna k mnohým strana ako strana vlastniaca:

verejná trieda ItemsOIO {// ... @ManyToOne @JoinColumn (name = "cart_id", insertable = false, updatable = false) súkromný košík CartOIO; // ..} verejná trieda CartOIO {// .. @OneToMany @JoinColumn (name = "cart_id") // musíme duplikovať fyzické informácie súkromné ​​položky Set; // ..} 

Všimnite si, ako sme odstránili mappedBy prvok a nastavte mnoho-na-jeden @ JoinColumn ako vložiteľný a aktualizovateľné do nepravdivé.

Ak spustíme rovnaký kód, bude výsledok opačný:

item1 ID = 1, ID košíka s cudzím kľúčom = 1 item2 ID = 2, ID košíka s cudzím kľúčom = 1

Ako je uvedené vyššie, teraz položka2 patrí vozík.

7. Záver

Videli sme, aké ľahké je implementovať jedna k mnohým vzťah s Hibernate ORM a H2 databázou pomocou anotácií JPA.

Ďalej sme sa dozvedeli o obojsmerných vzťahoch a o tom, ako implementovať pojem vlastniacej strany.

Zdrojový kód v tomto článku nájdete na GitHub.