什麼是JPA?Java Persistence API簡介

作爲規範, Java Persistence API 關注 持久性 ,它將Java對象的創建過程和具體的創建形式解耦。並非所有Java對象都需要持久化,但大多數應用程序都會保留關鍵業務對象。JPA規範允許您定義應該保留 哪些 對象,以及 如何 在Java應用程序中保留這些對象。

JPA本身不是一個工具或框架; 相反,它定義了一組可以由任何工具或框架實現的概念。雖然JPA的對象關係映射(ORM)模型最初基於 Hibernate ,但它已經發展了。同樣,雖然JPA最初打算用於關係/ SQL數據庫,但是一些JPA實現已經擴展用於NoSQL數據存儲。支持JPA和NoSQL的流行框架是 EclipseLink ,它是JPA 2.2的參考實現。

JPA和Hibernate

由於它們交織在一起的歷史,Hibernate和JPA經常混爲一談。但是,與 Java Servlet 規範一樣,JPA產生了許多兼容的工具和框架; Hibernate只是其中之一。

Hibernate 由Gavin King開發,於2002年初發布,是一個用於Java的ORM庫。King開發了Hibernate作爲 持久化實體bean 的 替代品 。該框架非常受歡迎,當時非常需要,它的許多想法都在第一個JPA規範中被採用和編纂。

今天, Hibernate ORM 是最成熟的JPA實現之一,並且仍然是Java中ORM的流行選項。 Hibernate ORM 5.3.8 (撰寫本文時的當前版本)實現了JPA 2.2。此外,Hibernate的工具系列已經擴展到包括 Hibernate Search , Hibernate Validator 和 Hibernate OGM 等流行工具,後者支持NoSQL的域模型持久性。

什麼是Java ORM?

雖然它們的執行不同,但每個JPA實現都提供某種ORM層。爲了理解JPA和JPA兼容的工具,您需要掌握ORM。

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

默認情況下,持久化對象的名稱將成爲表的名稱,字段將成爲列。設置表後,每個錶行對應於應用程序中的對象。對象映射是可配置的,但默認值往往效果很好。

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

 

配置Java ORM層

設置新項目以使用JPA時,需要配置數據存儲區和JPA提供程序。您將配置 數據存儲連接器 以連接到您選擇的數據庫(SQL或NoSQL)。您還將包含和配置 JPA提供程序 ,它是一個框架,如Hibernate或EclipseLink。雖然您可以手動配置JPA,但許多開發人員選擇使用Spring的開箱即用支持。有關手動和基於Spring的JPA安裝和設置的演示,請參閱下面的“ JPA安裝和設置 ”。

Java數據對象

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

Java中的數據持久性

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

使用JPA時,可以創建從數據存儲區到應用程序的數據模型對象的 映射 。您可以定義對象和數據庫之間的映射,而不是定義對象的保存和檢索方式,然後調用JPA來保存它們。如果您正在使用關係數據庫,那麼應用程序代碼和數據庫之間的大部分實際連接將由JDBC( Java數據庫連接API)處理 。

作爲規範,JPA提供 元數據註釋 ,您可以使用它來定義對象和數據庫之間的映射。每個JPA實現都爲JPA註釋提供了自己的引擎。JPA規範還提供了 PersistanceManager 或者 EntityManager ,它們是與JPA系統聯繫的關鍵點(其中您的業務邏輯代碼告訴系統如何處理映射對象)。

爲了使所有這些更具體,請考慮清單1,這是一個用於爲音樂家建模的簡單數據類。

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


 
public class Musician { private Long id; private String name; private Instrument mainInstrument; private ArrayList performances = new ArrayList<Performance>(); public Musician( Long id, String name){ /* constructor setters... */ } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setMainInstrument(Instrument instr){ this.instrument = instr; } public Instrument getMainInstrument(){ return this.instrument; } // ...Other getters and setters... } 

清單1中的 Musician 類用於保存數據。它可以包含原始數據,例如 名稱 字段。它還可以與其他類(如 mainInstrument 和 performances )保持關係。

Musician 存在的 原因 是包含數據。這種類有時稱爲DTO或 數據傳輸對象 。DTO是軟件開發的常見功能。雖然它們包含多種數據,但它們不包含任何業務邏輯。持久化數據對象是軟件開發中普遍存在的挑戰。

JDBC的數據持久性

將 Musician 類的實例保存到關係數據庫的一種方法是使用JDBC庫。JDBC是一個抽象層,它允許應用程序發出SQL命令而無需考慮底層數據庫實現。

清單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相比,它很麻煩。要修改數據庫,首先需要創建一個SQL查詢,該查詢從Java對象映射到關係數據庫中的表。然後,只要對象簽名發生更改,就必須修改SQL。使用JDBC,維護SQL本身就成了一項任務。

JPA的數據持久性

現在考慮清單3,我們使用JPA 持久化 Musician 類。

清單3.使用JPA保留George Harrison


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

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

JPA中的元數據註釋

清單3中的魔力是 配置 的結果,該 配置 是使用JPA的 註釋 創建的。開發人員使用註釋來告知JPA應該保留哪些對象,以及如何保留它們。

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

清單4. JPA的@Entity註釋


 
@Entity public class Musician { // ..class body } 

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

配置JPA

與大多數現代框架一樣,JPA 遵循約定編碼 (也稱爲約定優於配置),其中框架提供基於行業最佳實踐的默認配置。作爲一個示例,名爲 Musician 的類將默認映射到名爲 Musician 的數據庫表。

傳統配置是節省時間的,並且在許多情況下它運行良好。也可以自定義JPA配置。例如,您可以使用JPA的 @Table 註釋來指定應該存儲 Musician 類的表。

清單5. JPA的@Table註釋


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

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

主鍵

在JPA中, 主鍵 是用於唯一標識數據庫中每個對象的字段。主鍵可用於引用對象並將對象與其他實體相關聯。每當您在表中存儲對象時,您還將指定要用作其主鍵的字段。

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

清單6.指定主鍵


 
@Entity public class Musician { @Id private Long id; 

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

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

CRUD操作

將類映射到數據庫表並建立其主鍵後,即可擁有在數據庫中創建,檢索,刪除和更新該類所需的一切。調用 session.save() 將創建或更新指定的類,具體取決於主鍵字段是否爲null或是否適用於現有實體。調用 entityManager.remove() 將刪除指定的類。

JPA中的實體關係

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

  1. 一到多
  2. 許多到一
  3. 許多一對多
  4. 一比一

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

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

如果 Musician 包含 BandMates 字段,則可以表示與其他 Musician 實體 的多對多關係

最後, Musician 可能與 Quote 實體有 一對一的關係 ,用於表示一個着名的引語: Quote famousQuote = new Quote() 。

定義關係類型

JPA爲每種關係映射類型提供註解。清單7顯示瞭如何註解 Musician 和 Performance s 之間的一對多關係。

清單7.註釋一對多關係


 
public class Musician { @OneToMany @JoinColumn(name="musicianId") private List<Performance> performances = new ArrayList<Performance>(); //... } 

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

在JPA中獲取策略

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

我們需要的是定義相關實體的 延遲加載 的能力- 當然,認識到 JPA 中的 關係可能是eager或 lazy的。您可以使用註釋來自定義提取策略,但JPA的默認配置通常可以直接使用,無需更改:

  1. 一對多:lazy
  2. 多對一:eager
  3. 多對多:lazy
  4. 一對一:eager

JPA安裝和設置

最後,我們將簡要介紹如何爲Java應用程序安裝和設置JPA。在本演示中,我將使用EclipseLink,即JPA參考實現。

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

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


 
org.eclipse.persistence eclipselink 2.5.0-RC1 

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

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


 
mysql mysql-connector-java 5.1.32 

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

清單10. Persistence.xml


 
http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="MyUnit" transaction-type="RESOURCE_LOCAL"> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/foo_bar"/> <property name="javax.persistence.jdbc.user" value=""/> <property name="javax.persistence.jdbc.password" value=""/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> </properties> </persistence-unit> </persistence> 

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

清單10. Persistence.xml


 
http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="MyUnit" transaction-type="RESOURCE_LOCAL"> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/foo_bar"/> <property name="javax.persistence.jdbc.user" value=""/> <property name="javax.persistence.jdbc.password" value=""/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> </properties> </persistence-unit> </persistence> 

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

JPA的Spring配置

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

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

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


 
org.springframework.boot spring-boot-starter 2.1.3.RELEASE org.springframework.boot spring-boot-starter-data-jpa 2.1.3.RELEASE 

結論

處理數據庫的每個應用程序都應該定義一個應用程序層,其唯一目的是隔離持久性代碼。正如您在本文中看到的,Java Persistence API引入了一系列功能並支持Java對象持久性。簡單的應用程序可能不需要JPA的所有功能,在某些情況下,配置框架的開銷可能不值得。然而,隨着應用程序的增長,JPA的結構和封裝確實能夠保持不變。使用JPA可以簡化目標代碼,並提供用於訪問Java應用程序中的數據的傳統框架。


喜歡的點點關注,點點贊。

對Java技術,架構技術感興趣的同學,歡迎加QQ羣585550789,一起學習,相互討論。

羣內已經有小夥伴將知識體系整理好(源碼,筆記,PPT,學習視頻),歡迎加羣領取。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章