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 má 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 BigInteger
nebo 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ý profil
je 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 Autor
s:
@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 aDotaz
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
definujeEntityTransaction
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. ThegetTransaction ()
metoda umožňuje přístup k tomuto chování na úrovniEntityManager
, 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.