什么是JPA擦耀?Java Persistence API簡介

作為規(guī)范,?Java Persistence API?關注?持久性?榕酒,它將Java對象的創(chuàng)建過程和具體的創(chuàng)建形式解耦胚膊。并非所有Java對象都需要持久化,但大多數應用程序都會保留關鍵業(yè)務對象想鹰。JPA規(guī)范允許您定義應該保留?哪些?對象紊婉,以及?如何?在Java應用程序中保留這些對象。

JPA本身不是一個工具或框架; 相反辑舷,它定義了一組可以由任何工具或框架實現(xiàn)的概念喻犁。雖然JPA的對象關系映射(ORM)模型最初基于?Hibernate?,但它已經發(fā)展了。同樣肢础,雖然JPA最初打算用于關系/ SQL數據庫还栓,但是一些JPA實現(xiàn)已經擴展用于NoSQL數據存儲。支持JPA和NoSQL的流行框架是?EclipseLink?传轰,它是JPA 2.2的參考實現(xiàn)蝙云。

JPA和Hibernate

由于它們交織在一起的歷史,Hibernate和JPA經陈氛伲混為一談。但是波材,與?Java Servlet?規(guī)范一樣股淡,JPA產生了許多兼容的工具和框架; Hibernate只是其中之一。

Hibernate?由Gavin King開發(fā)廷区,于2002年初發(fā)布唯灵,是一個用于Java的ORM庫。King開發(fā)了Hibernate作為?持久化實體bean?的?替代品?隙轻。該框架非常受歡迎埠帕,當時非常需要,它的許多想法都在第一個JPA規(guī)范中被采用和編纂玖绿。

今天敛瓷,?Hibernate ORM?是最成熟的JPA實現(xiàn)之一,并且仍然是Java中ORM的流行選項斑匪。?Hibernate ORM 5.3.8?(撰寫本文時的當前版本)實現(xiàn)了JPA 2.2呐籽。此外,Hibernate的工具系列已經擴展到包括?Hibernate Search?蚀瘸,?Hibernate Validator?和?Hibernate OGM?等流行工具狡蝶,后者支持NoSQL的域模型持久性。

什么是Java ORM贮勃?

雖然它們的執(zhí)行不同贪惹,但每個JPA實現(xiàn)都提供某種ORM層。為了理解JPA和JPA兼容的工具寂嘉,您需要掌握ORM奏瞬。

對象關系映射是一項?任務?- 開發(fā)人員有充分的理由避免手動執(zhí)行。像Hibernate ORM或EclipseLink這樣的框架將該任務編碼為庫或框架垫释,即?ORM層?丝格。作為應用程序體系結構的一部分,ORM層負責管理軟件對象的轉換棵譬,以便與關系數據庫中的表和列進行交互显蝌。在Java中,ORM層轉換Java類和對象,以便可以在關系數據庫中存儲和管理它們曼尊。

默認情況下酬诀,持久化對象的名稱將成為表的名稱,字段將成為列骆撇。設置表后瞒御,每個表行對應于應用程序中的對象。對象映射是可配置的神郊,但默認值往往效果很好肴裙。

圖1說明了JPA和ORM層在應用程序開發(fā)中的作用。

配置Java ORM層

設置新項目以使用JPA時涌乳,需要配置數據存儲區(qū)和JPA提供程序蜻懦。您將配置?數據存儲連接器?以連接到您選擇的數據庫(SQL或NoSQL)。您還將包含和配置?JPA提供程序?夕晓,它是一個框架宛乃,如Hibernate或EclipseLink。雖然您可以手動配置JPA蒸辆,但許多開發(fā)人員選擇使用Spring的開箱即用支持征炼。有關手動和基于Spring的JPA安裝和設置的演示,請參閱下面的“?JPA安裝和設置?”躬贡。

Java數據對象

Java Data Objects是一個標準化的持久性框架谆奥,它與JPA的不同之處主要在于支持對象中的持久性邏輯,以及它長期以來對使用非關系數據存儲的支持逗宜。JPA和JDO足夠相似雄右,JDO提供者也經常支持JPA。請參閱?Apache JDO項目?纺讲,以了解有關JDO與JPA和JDBC等其他持久性標準相關的更多信息擂仍。

Java中的數據持久性

從編程的角度來看,ORM層是一個?適配器層?:它使對象圖的語言適應SQL和關系表的語言熬甚。ORM層允許面向對象的開發(fā)人員構建持久保存數據的軟件逢渔,而無需離開面向對象的范例。

使用JPA時乡括,可以創(chuàng)建從數據存儲區(qū)到應用程序的數據模型對象的?映射?肃廓。您可以定義對象和數據庫之間的映射,而不是定義對象的保存和檢索方式诲泌,然后調用JPA來保存它們盲赊。如果您正在使用關系數據庫,那么應用程序代碼和數據庫之間的大部分實際連接將由JDBC(?Java數據庫連接API)處理?敷扫。

作為規(guī)范哀蘑,JPA提供?元數據注釋?,您可以使用它來定義對象和數據庫之間的映射。每個JPA實現(xiàn)都為JPA注釋提供了自己的引擎绘迁。JPA規(guī)范還提供了 PersistanceManager 或者 EntityManager 合溺,它們是與JPA系統(tǒng)聯(lián)系的關鍵點(其中您的業(yè)務邏輯代碼告訴系統(tǒng)如何處理映射對象)。

為了使所有這些更具體缀台,請考慮清單1棠赛,這是一個用于為音樂家建模的簡單數據類。

清單1. Java中的一個簡單數據類

publicclassMusician{privateLong id;privateString name;privateInstrument mainInstrument;privateArrayList performances =newArrayList();publicMusician( Long id, String name){/* constructor setters... */}publicvoidsetName(String name){this.name = name; }publicStringgetName(){returnthis.name; }publicvoidsetMainInstrument(Instrument instr){this.instrument = instr; }publicInstrumentgetMainInstrument(){returnthis.instrument; }// ...Other getters and setters...}

清單1中的 Musician 類用于保存數據膛腐。它可以包含原始數據睛约,例如?名稱?字段。它還可以與其他類(如 mainInstrument 和 performances )保持關系哲身。

Musician 存在的?原因?是包含數據痰腮。這種類有時稱為DTO或?數據傳輸對象?。DTO是軟件開發(fā)的常見功能律罢。雖然它們包含多種數據,但它們不包含任何業(yè)務邏輯棍丐。持久化數據對象是軟件開發(fā)中普遍存在的挑戰(zhàn)误辑。

JDBC的數據持久性

將 Musician 類的實例保存到關系數據庫的一種方法是使用JDBC庫。JDBC是一個抽象層歌逢,它允許應用程序發(fā)出SQL命令而無需考慮底層數據庫實現(xiàn)巾钉。

清單2顯示了如何使用JDBC 來持久化 Musician 類。

清單2.插入記錄的JDBC

Musician georgeHarrison = new Musician(0,"George Harrison"); String myDriver ="org.gjt.mm.mysql.Driver"; String myUrl ="jdbc:mysql://localhost/test"; Class.forName(myDriver); Connection conn = DriverManager.getConnection(myUrl,"root",""); String query =" insert into users (id, name) values (?, ?)"; PreparedStatement preparedStmt = conn.prepareStatement(query); preparedStmt.setInt (1,0); preparedStmt.setString (2,"George Harrison"); preparedStmt.setString (2,"Rubble"); preparedStmt.execute(); conn.close();// Error handling removed for brevity

清單2中的代碼是相當自我記錄的秘案。該 georgeHarrison 對象可以來自任何地方(前端提交砰苍,外部服務等),并設置其ID和name字段阱高。然后赚导,對象上的字段用于提供SQL insert 語句的值。( PreparedStatement 該類是JDBC的一部分赤惊,提供了一種將值安全地應用于SQL查詢的方法吼旧。)

雖然JDBC允許手動配置附帶的控件,但與JPA相比未舟,它很麻煩圈暗。要修改數據庫,首先需要創(chuàng)建一個SQL查詢裕膀,該查詢從Java對象映射到關系數據庫中的表员串。然后,只要對象簽名發(fā)生更改昼扛,就必須修改SQL寸齐。使用JDBC,維護SQL本身就成了一項任務。

JPA的數據持久性

現(xiàn)在考慮清單3访忿,我們使用JPA 持久化 Musician 類瞧栗。

清單3.使用JPA保留George Harrison

Musician georgeHarrison =newMusician(0,"George Harrison");musicianManager.save(georgeHarrison);

清單3用一行 session.save() 替換了清單2中的手動SQL ,它指示JPA持久保存該對象海铆。從那時起迹恐,SQL轉換由框架處理,因此您永遠不必離開面向對象的范例卧斟。

JPA中的元數據注釋

清單3中的魔力是?配置?的結果殴边,該?配置?是使用JPA的?注釋?創(chuàng)建的。開發(fā)人員使用注釋來告知JPA應該保留哪些對象珍语,以及如何保留它們锤岸。

清單4顯示了具有單個JPA注釋的 Musician 類。

清單4. JPA的@Entity注釋

@EntitypublicclassMusician{// ..class body}

持久對象有時稱為?實體?板乙。附加 @Entity 到類是偷, Musician 告知JPA應該保留此類及其對象。

配置JPA

與大多數現(xiàn)代框架一樣募逞,JPA?遵循約定編碼?(也稱為約定優(yōu)于配置)蛋铆,其中框架提供基于行業(yè)最佳實踐的默認配置。作為一個示例放接,名為 Musician 的類將默認映射到名為?Musician?的數據庫表刺啦。

傳統(tǒng)配置是節(jié)省時間的,并且在許多情況下它運行良好纠脾。也可以自定義JPA配置玛瘸。例如,您可以使用JPA的 @Table 注釋來指定應該存儲 Musician 類的表苟蹈。

清單5. JPA的@Table注釋

@Entity@Table(name="musician")public class Musician {// ..class body}

清單5告訴JPA將實體( Musician 類)持久化到 musician 表中糊渊。

主鍵

在JPA中,?主鍵?是用于唯一標識數據庫中每個對象的字段慧脱。主鍵可用于引用對象并將對象與其他實體相關聯(lián)再来。每當您在表中存儲對象時,您還將指定要用作其主鍵的字段磷瘤。

在清單6中芒篷,我們告訴JPA要使用哪個字段作為 Musician 主鍵。

清單6.指定主鍵

@EntitypublicclassMusician{@IdprivateLongid;

在這種情況下采缚,我們使用JPA的 @Id 注釋將 id 字段指定為 Musician 主鍵针炉。默認情況下,此配置假定主鍵將由數據庫設置 - 例如扳抽,當字段設置為在表上自動遞增時篡帕。

JPA支持生成對象主鍵的其他策略殖侵。它還有用于更改單個字段名稱的注釋。通常镰烧,JPA足夠靈活拢军,可以適應您可能需要的任何持久性映射。

CRUD操作

將類映射到數據庫表并建立其主鍵后怔鳖,即可擁有在數據庫中創(chuàng)建茉唉,檢索,刪除和更新該類所需的一切结执。調用 session.save() 將創(chuàng)建或更新指定的類度陆,具體取決于主鍵字段是否為null或是否適用于現(xiàn)有實體。調用 entityManager.remove() 將刪除指定的類献幔。

JPA中的實體關系

簡單地使用原始字段持久化對象只是方程式的一半懂傀。JPA還具有管理彼此相關實體的能力。在表和對象中都有四種實體關系:

一到多

許多到一

許多一對多

一比一

每種類型的關系描述了實體與其他實體的關系蜡感。例如蹬蚁, Musician 實體可以與由諸如 List 或 Set 的集合表示的實體具有?一對多的關系?。

如果 Musician 包含一個 Band 字段郑兴,這些實體之間的關系可以是?多對一的?缚忧,這意味著在單個 Band 類上有 Musician集合 。(假設每個音樂家只在一個樂隊中演奏杈笔。)

如果 Musician 包含 BandMates 字段,則可以表示與其他 Musician 實體?的多對多關系糕非。

最后蒙具, Musician 可能與 Quote 實體有?一對一的關系?,用于表示一個著名的引語: Quote famousQuote = new Quote() 朽肥。

定義關系類型

JPA為每種關系映射類型提供注解禁筏。清單7顯示了如何注解 Musician 和 Performance s 之間的一對多關系。

清單7.注釋一對多關系

publicclassMusician{@OneToMany@JoinColumn(name="musicianId") private List performances = new ArrayList();//...}

需要注意的一點是 @JoinColumn 告訴JPA?Performance?表上的哪一列將映射到 Musician 實體衡招。每個performance都將與單個 Musician 關聯(lián)篱昔,該列由此列跟蹤。當JPA將一個 Musician 或一個 Performance 加載到數據庫中時始腾,它將使用此信息重新構建對象圖州刽。

在JPA中獲取策略

除了知道??數據庫中放置相關實體??的位置之外,JPA還需要知道?如何?加載它們浪箭。?獲取策略?告訴JPA如何加載相關實體穗椅。加載和保存對象時,JPA框架必須能夠微調對象圖的處理方式奶栖。例如匹表,如果 Musician 類有一個 bandMate 字段(如清單7所示)门坷,加載 george 可能導致整個?Musician?表從數據庫加載!

我們需要的是定義相關實體的?延遲加載?的能力- 當然袍镀,認識到?JPA?中的?關系可能是eager或?lazy的默蚌。您可以使用注釋來自定義提取策略,但JPA的默認配置通澄郏可以直接使用绸吸,無需更改:

一對多:lazy

多對一:eager

多對多:lazy

一對一:eager

JPA安裝和設置

最后,我們將簡要介紹如何為Java應用程序安裝和設置JPA宣虾。在本演示中惯裕,我將使用EclipseLink,即JPA參考實現(xiàn)绣硝。

安裝JPA的常用方法是在項目中?包含?JPA提供程序蜻势。清單8顯示了如何將EclipseLink作為Maven pom.xml 文件中的依賴項包含在內。

清單8.將EclipseLink包含為Maven依賴項

org.eclipse.persistenceeclipselink2.5.0-RC1

您還需要包含數據庫的驅動程序鹉胖,如清單9所示握玛。

清單9. MySql連接器的Maven依賴關系

mysqlmysql-connector-java5.1.32

接下來,您需要告訴系統(tǒng)您的數據庫和提供程序甫菠。這在 persistence.xml 文件中完成挠铲,如清單10所示。

清單10. Persistence.xml

http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

還有其他方法可以向系統(tǒng)提供此信息寂诱,包括以編程方式拂苹。我建議使用該 persistence.xml 文件,因為以這種方式存儲依賴項使得在不修改代碼的情況下更新應用程序非常容易痰洒。

清單10. Persistence.xml

http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

還有其他方法可以向系統(tǒng)提供此信息瓢棒,包括以編程方式。我建議使用該 persistence.xml 文件丘喻,因為以這種方式存儲依賴項使得在不修改代碼的情況下更新應用程序非常容易脯宿。

JPA的Spring配置

使用Spring將極大地簡化JPA與應用程序的集成。例如泉粉,將 @SpringBootApplication 注釋放在應用程序頭中會指示Spring 根據您指定的配置自動掃描類并根據需要注入 EntityManager 连霉。

如果您希望Spring為您的應用程序提供JPA支持,清單11顯示了要包含的依賴項嗡靡。

清單11.在Maven中添加Spring JPA支持

org.springframework.bootspring-boot-starter2.1.3.RELEASEorg.springframework.bootspring-boot-starter-data-jpa2.1.3.RELEASE

結論

處理數據庫的每個應用程序都應該定義一個應用程序層跺撼,其唯一目的是隔離持久性代碼。正如您在本文中看到的讨彼,Java Persistence API引入了一系列功能并支持Java對象持久性财边。簡單的應用程序可能不需要JPA的所有功能,在某些情況下点骑,配置框架的開銷可能不值得酣难。然而谍夭,隨著應用程序的增長,JPA的結構和封裝確實能夠保持不變憨募。使用JPA可以簡化目標代碼紧索,并提供用于訪問Java應用程序中的數據的傳統(tǒng)框架。

喜歡的點點關注菜谣,點點贊珠漂。

對Java技術,架構技術感興趣的同學尾膊,歡迎加QQ群585550789媳危,一起學習,相互討論冈敛。

群內已經有小伙伴將知識體系整理好(源碼待笑,筆記,PPT抓谴,學習視頻)暮蹂,歡迎加群領取。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末癌压,一起剝皮案震驚了整個濱河市仰泻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滩届,老刑警劉巖集侯,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帜消,居然都是意外死亡棠枉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門券犁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人汹碱,你說我怎么就攤上這事粘衬。” “怎么了咳促?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵稚新,是天一觀的道長。 經常有香客問我跪腹,道長褂删,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任冲茸,我火速辦了婚禮屯阀,結果婚禮上缅帘,老公的妹妹穿的比我還像新娘。我一直安慰自己难衰,他們只是感情好钦无,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盖袭,像睡著了一般失暂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鳄虱,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天弟塞,我揣著相機與錄音,去河邊找鬼拙已。 笑死决记,一個胖子當著我的面吹牛,可吹牛的內容都是我干的悠栓。 我是一名探鬼主播霉涨,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惭适!你這毒婦竟也來了笙瑟?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤癞志,失蹤者是張志新(化名)和其女友劉穎往枷,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體凄杯,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡错洁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了戒突。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屯碴。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膊存,靈堂內的尸體忽然破棺而出导而,到底是詐尸還是另有隱情,我是刑警寧澤隔崎,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布今艺,位于F島的核電站,受9級特大地震影響爵卒,放射性物質發(fā)生泄漏虚缎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一钓株、第九天 我趴在偏房一處隱蔽的房頂上張望实牡。 院中可真熱鬧陌僵,春花似錦、人聲如沸铲掐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摆霉。三九已至豪椿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間携栋,已是汗流浹背搭盾。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留婉支,地道東北人鸯隅。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像向挖,于是被迫代替她去往敵國和親蝌以。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容