Programování

Persistence prostředí Java s JPA a Hibernate, část 1: Entity a vztahy

Java Persistence API (JPA) je specifikace Java, která překlenuje propast mezi relačními databázemi a objektově orientovaným programováním. Tento dvoudílný tutoriál představuje JPA a vysvětluje, jak jsou objekty Java modelovány jako entity JPA, jak jsou definovány vztahy entit a jak používat JPA EntityManager se vzorem Repository ve vašich aplikacích Java.

Všimněte si, že tento výukový program používá Hibernate jako poskytovatele JPA. Většinu konceptů lze rozšířit na další rámce persistence Java.

Co je to JPA?

V části „Co je to JPA? Úvod do rozhraní Java Persistence API“ se dozvíte o vývoji JPA a souvisejících rámců, včetně EJB 3.0. a JDBC.

Objektové vztahy v JPA

Relační databáze existují jako prostředek pro ukládání programových dat od 70. let. Zatímco vývojáři dnes mají k relační databázi mnoho alternativ, tento typ databáze je škálovatelný a dobře srozumitelný a stále se široce používá při vývoji softwaru v malém i velkém měřítku.

Objekty Java v kontextu relační databáze jsou definovány jako subjekty. Entity jsou umístěny v tabulkách, kde zabírají sloupce a řádky. Programátoři používají cizí klíče a spojit tabulky definovat vztahy mezi entitami - konkrétně vztahy jedna ku jedné, vztahy jedna k mnoha a mnoho z mnoha. Můžeme také použít SQL (Structured Query Language) k načtení a interakci s daty v jednotlivých tabulkách a ve více tabulkách pomocí omezení cizího klíče. Relační model je plochý, ale vývojáři mohou psát dotazy k načtení dat a konstrukci objektů z těchto dat.

Neshoda impedance objektových vztahů

Tento pojem možná znáte nesoulad impedance objektových vztahů, který odkazuje na výzvu mapování datových objektů do relační databáze. K tomuto nesouladu dochází, protože objektově orientovaný design není omezen na vztahy jeden na jednoho, jeden na mnoho a mnoho na mnoho. Místo toho v objektově orientovaném designu myslíme na objekty, jejich atributy a chování a na to, jak objekty souvisejí. Dva příklady jsou zapouzdření a dědičnost:

  • Pokud objekt obsahuje jiný objekt, definujeme to prostřednictvím zapouzdření--A vztah.
  • Pokud je objekt specializací jiného objektu, definujeme to prostřednictvím dědictví--an je vztah.

Asociace, agregace, složení, abstrakce, zobecnění, realizace a závislosti - to vše jsou koncepty objektově orientovaného programování, jejichž mapování na relační model může být náročné.

ORM: Objektově relační mapování

Neshoda mezi objektově orientovaným designem a modelováním relační databáze vedla k vytvoření třídy nástrojů vyvinutých speciálně pro objektově-relační mapování (ORM). Nástroje ORM jako Hibernate, EclipseLink a iBatis překládají modely relačních databází, včetně entit a jejich vztahů, do objektově orientovaných modelů. Mnoho z těchto nástrojů existovalo před specifikací JPA, ale bez standardu byly jejich funkce závislé na dodavateli.

Rozhraní Java Persistence API (JPA), které bylo poprvé vydáno jako součást EJB 3.0 v roce 2006, nabízí standardní způsob anotace objektů, aby mohly být mapovány a uloženy v relační databázi. Specifikace také definuje společný konstrukt pro interakci s databázemi. Standard ORM pro Javu přináší konzistenci implementací dodavatelů a zároveň umožňuje flexibilitu a doplňky. Například, zatímco původní specifikace JPA je použitelná pro relační databáze, některé implementace dodavatelů rozšířily JPA pro použití s ​​databázemi NoSQL.

Vývoj JPA

První vydání JPA, verze 1.0, bylo vydáno v roce 2006 prostřednictvím Java Community Process (JCP) jako Java Specification Request (JSR) 220. Verze 2.0 (JSR 317) byla vydána v roce 2009, verze 2.1 (JSR 338) v roce 2013, a verze 2.2 (servisní vydání JSR 338) byla zveřejněna v roce 2017. Pro zařazení a pokračující vývoj v Jakartě EE byl vybrán JPA 2.2.

Začínáme s JPA

Rozhraní Java Persistence API je specifikace, nikoli implementace: definuje běžnou abstrakci, kterou můžete použít ve svém kódu k interakci s produkty ORM. V této části jsou uvedeny některé důležité části specifikace JPA.

Dozvíte se, jak:

  • Definujte entity, pole a primární klíče v databázi.
  • Vytvořte vztahy mezi entitami v databázi.
  • Práce s EntityManager a jeho metody.

Definování entit

Chcete-li definovat entitu, musíte vytvořit třídu, která je anotována pomocí @Entity anotace. The @Entity anotace je a anotace značky, který se používá k objevení trvalých entit. Pokud byste například chtěli vytvořit entitu knihy, přidali byste k ní následující poznámky:

 @Entity Public Class Book {...} 

Ve výchozím nastavení bude tato entita mapována na Rezervovat tabulka, jak je určeno daným názvem třídy. Pokud jste chtěli tuto entitu namapovat na jinou tabulku (a volitelně na konkrétní schéma), můžete použít @Stůl anotace k tomu. Takto byste mapovali Rezervovat třída do tabulky KNIHY:

 @Entity @Table (name = "KNIHY") veřejná třída Kniha {...} 

Pokud byla tabulka KNIHY ve schématu PUBLISHING, můžete schéma přidat do @Stůl anotace:

 @Table (name = "BOOKS", schema = "PUBLISHING") 

Mapování polí na sloupce

S entitou namapovanou na tabulku je vaším dalším úkolem definovat její pole. Pole jsou definovány jako členské proměnné ve třídě, přičemž název každého pole je mapován na název sloupce v tabulce. Toto výchozí mapování můžete přepsat pomocí @Sloupec anotace, jak je znázorněno zde:

 @Entity @Table (name = "KNIHY") veřejná třída Book {private String name; @Column (name = "ISBN_NUMBER") soukromý řetězec isbn; ...} 

V tomto příkladu jsme přijali výchozí mapování pro název atribut, ale zadal vlastní mapování pro isbn atribut. The název atribut bude mapován na název sloupec, ale isbn atribut bude namapován na sloupec ISBN_NUMBER.

The @Sloupec anotace nám umožňuje definovat další vlastnosti pole / sloupce, včetně délky, zda má povolenou hodnotu Null, zda musí být jedinečné, jeho přesnosti a měřítka (je-li to desetinná hodnota), zda je vložitelné a aktualizovatelné atd.

Zadání primárního klíče

Jedním z požadavků na tabulku relačních databází je, že musí obsahovat a primární klíčnebo klíč, který jednoznačně identifikuje konkrétní řádek v databázi. V JPA používáme @Id anotace k označení pole jako primárního klíče tabulky. Primární klíč musí být primitivní typ Java, primitivní obálka, například Celé číslo nebo Dlouho, a Tětiva, a datum, a BigIntegernebo BigDecimal.

V tomto příkladu mapujeme id atribut, kterým je Celé číslo, do sloupce ID v tabulce KNIHY:

 @Entity @Table (name = "KNIHY") veřejná třída Book {@Id private Integer id; soukromé jméno řetězce; @Column (name = "ISBN_NUMBER") soukromý řetězec isbn; ...} 

Je také možné kombinovat @Id anotace s @Sloupec anotace přepsat mapování názvů sloupců primárního klíče.

Vztahy mezi entitami

Nyní, když víte, jak definovat entitu, pojďme se podívat na to, jak vytvořit vztahy mezi entitami. SPS definuje čtyři anotace pro definování entit:

  • @OneToOne
  • @OneToMany
  • @ManyToOne
  • @ManyToMany

Osobní vztahy

The @OneToOne anotace se používá k definování vztahu jedna k jedné mezi dvěma entitami. Můžete mít například a Uživatel entita, která obsahuje uživatelské jméno, e-mail a heslo, ale možná budete chtít zachovat další informace o uživateli (například věk, pohlaví a oblíbenou barvu) v samostatném Uživatelský profil subjekt. The @OneToOne anotace tímto způsobem usnadňuje rozdělení vašich dat a entit.

The Uživatel třída níže má jeden Uživatelský profil instance. The Uživatelský profil mapy do jednoho Uživatel instance.

 @Entity veřejná třída Uživatel {@Id soukromé celé číslo; soukromý řetězcový e-mail; soukromé jméno řetězce; soukromé heslo řetězce; @OneToOne (mappedBy = "uživatel") soukromý profil UserProfile; ...} 
 @Entity veřejná třída UserProfile {@Id soukromé celé číslo; soukromý věk; soukromý řetězec; private String oblíbenéColor; @OneToOne soukromý uživatel uživatele; ...} 

Poskytovatel JPA používá Uživatelský profilje uživatel pole k mapování Uživatelský profil na Uživatel. Mapování je specifikováno v mappedBy atribut v @OneToOne anotace.

Vztahy one-to-many and many-to-one

The @OneToMany a @ManyToOne anotace usnadňují obě strany stejného vztahu. Zvažte příklad, kdy a Rezervovat může mít jen jednu Autor, ale Autor může mít mnoho knih. The Rezervovat entita by definovala a @ManyToOne vztah s Autor a Autor entita by definovala a @OneToMany vztah s Rezervovat.

 @Entity public class Book {@Id private Integer id; soukromé jméno řetězce; @ManyToOne @JoinColumn (name = "AUTHOR_ID") soukromý autor autor; ...} 
 @Entity veřejná třída Autor {@Id @GeneratedValue soukromé celé číslo; soukromé jméno řetězce; @OneToMany (mappedBy = "autor") soukromé seznamy knih = nový ArrayList (); ...} 

V tomto případě Autor třída udržuje seznam všech knih napsaných tímto autorem a Rezervovat třída udržuje odkaz na svého jediného autora. Navíc @JoinColumn určuje název sloupce v Rezervovat tabulka pro uložení ID Autor.

Vztahy mnoho k mnoha

Nakonec @ManyToMany anotace usnadňuje vztah mezi entitami mezi entitami. Zde je případ, kdy a Rezervovat entita má více Autors:

 @Entity public class Book {@Id private Integer id; soukromé jméno řetězce; @ManyToMany @JoinTable (name = "BOOK_AUTHORS", joinColumns = @ JoinColumn (name = "BOOK_ID"), inverseJoinColumns = @ JoinColumn (name = "AUTHOR_ID")) soukromá sada autorů = nová HashSet (); ...} 
 @Entity veřejná třída Autor {@Id @GeneratedValue soukromé celé číslo; soukromé jméno řetězce; @ManyToMany (mappedBy = "autor") soukromá sada knih = nová HashSet (); ...} 

V tomto příkladu vytvoříme novou tabulku, BOOK_AUTHORS, se dvěma sloupci: BOOK_ID a AUTHOR_ID. Za použití joinColumns a inverseJoinColumns atributy řeknou vašemu rámci JPA, jak mapovat tyto třídy ve vztahu mnoho k mnoha. The @ManyToMany anotace v Autor třída odkazuje na pole v souboru Rezervovat třída, která řídí vztah; jmenovitě autoři vlastnictví.

To je rychlá ukázka pro poměrně složité téma. Ponoříme se dále do @JoinTable a @JoinColumn anotace v příštím článku.

Práce s EntityManager

EntityManager je třída, která provádí databázové interakce v JPA. Inicializuje se pomocí konfiguračního souboru s názvem persistence.xml. Tento soubor se nachází v META-INF složku ve vašem CLASSPATH, který je obvykle zabalen ve vašem souboru JAR nebo WAR. The persistence.xml soubor obsahuje:

  • Pojmenovaná „jednotka perzistence“, která určuje rámec perzistence, který používáte, například Hibernate nebo EclipseLink.
  • Kolekce vlastností určujících, jak se připojit k vaší databázi, stejně jako veškerá přizpůsobení v rámci perzistence.
  • Seznam tříd entit ve vašem projektu.

Podívejme se na příklad.

Konfigurace EntityManageru

Nejprve vytvoříme EntityManager za použití EntityManagerFactory získaný z Vytrvalost třída:

 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory ("Knihy"); EntityManager entityManager = entityManagerFactory.createEntityManager (); 

V tomto případě jsme vytvořili EntityManager který je připojen k jednotce perzistence "Knihy", kterou jsme nakonfigurovali v persistence.xml soubor.

The EntityManager třída definuje, jak bude náš software interagovat s databází prostřednictvím entit JPA. Zde jsou některé z metod, které používá EntityManager:

  • nalézt načte entitu podle jejího primárního klíče.
  • createQuery vytváří Dotaz instance, kterou lze použít k načtení entit z databáze.
  • createNamedQuery načte a Dotaz který byl definován v a @NamedQuery anotace uvnitř jedné z entit perzistence. Pojmenované dotazy poskytnout čistý mechanismus pro centralizaci dotazů JPA v definici třídy perzistence, na které se dotaz spustí.
  • getTransaction definuje EntityTransaction použít ve vašich databázových interakcích. Stejně jako u transakcí v databázi obvykle zahájíte transakci, provedete operace a poté transakci potvrdíte nebo odvoláte. The getTransaction () metoda umožňuje přístup k tomuto chování na úrovni EntityManager, spíše než databáze.
  • spojit() přidá entitu do kontextu perzistence, takže při potvrzení transakce bude entita přetrvávat do databáze. Při použití spojit(), objekty nejsou spravovány.
  • přetrvávat přidá entitu do kontextu perzistence, takže při potvrzení transakce bude entita přetrvávat do databáze. Při použití přetrvávat (), objekty jsou spravovány.
  • Obnovit aktualizuje stav aktuální entity z databáze.
  • flush synchronizuje stav kontextu perzistence s databází.

Nedělejte si starosti s integrací všech těchto metod najednou. Poznáte je tím, že budete pracovat přímo s EntityManager, které v další části uděláme více.