下篇:可治理的POJO持久性
在java虛擬機(JVM)里面,所有數據都被建模,并且被封裝在樹結構的類和對象中。然而,在后端關系數據庫中,數據被建模成關系表,它們通過共享的鍵字段相互關聯起來。同一數據卻有兩個不同的視圖,這給企業Java的開發人員帶來了挑戰:假如你要把數據保存到持久性數據存儲區,或者從持久性數據存儲區獲取數據,就必須在對象和關系表示之間往返轉換數據,這個過程就叫作對象-關系映射(ORM)。在Java EE(Java企業版,以前叫J2EE)中,可以通過兩個方法來完成對象-關系映射。
● 人工方法:使用Java數據庫連接性(JDBC)直接處理持久性——這個簡單的解決方法適用于簡單的應用程序。JDBC API的類緊密地按照關系數據庫里面的表、行和列進行建模。但必須在應用程序的內部對象模型和JDBC對象模型之間進行人工轉換,假如應用程序的內部模型已經類似二維關系表,采用JDBC是最佳方法。
● 自動方法:可以把ORM任務交給框架去處理。框架通常提供了可以處理任何數據對象的API。通過這個API,可以保存、獲取及查找數據庫。框架在后臺完成對象-關系的轉換。因為針對特定關系的SQL查詢不適合對象接口,ORM框架通常定義了自己的查詢語言,可以為當前的關系數據庫自動生成正確的SQL語句。對數據模型復雜的應用程序而言,基于框架的方法可以節省許多時間,并且減少出錯。
ORM 框架
EJB 實體bean是Java EE中的“官方”ORM解決方案。不過在EJB1.x和2.x中,實體bean使用起來非常困難,這有兩個原因:
● EJB 1.x和2.x實體bean必須符合嚴格的組件模型。每個bean類必須實現本地接口和業務接口。它們必須從某些抽象類繼續而來,還要實現所有方法,即便許多方法是空的。有了這樣一種嚴格的組件模型,就不可能利用EJB 1.x和2.x實體bean來構建面向對象的數據模型。
● EJB 1.x和2.x容器需要極其冗長的xml配置文件把實體bean映射到關系數據庫里面的表。那些文件非常冗長,還輕易出錯。
簡而言之,EJB 1.x和2.x實體bean是一種設計拙劣的ORM框架,既滿足不了Java數據對象模型的需求,也滿足不了關系表數據模型的需求。出于對EJB 1.x和2.x實體bean的不滿,開發人員尋求ORM的其他方案。在實際環境中,采用開放源代碼的Hibernate(由JBoss公司開發)和Oracle公司的TopLink是兩個最成功的Java ORM框架。Hibernate和TopLink都基于POJO:它們不依靠任何預定義的組件模型。相反,它們獲得POJO數據對象(采用簡單的JavaBean格式)后,會自動解釋如何把這些數據對象以及它們之間的關系映射到關系數據庫。通常,一個JavaBean類映射到一張數據庫表,類之間的關系通過表里面的外來鍵字段進行映射。可以在簡單、直觀的XML配置文件里面指定ORM元數據,譬如與JavaBean類相對應的表名以及與屬性相對應的列名。可以通過框架中的工具類(如Hibernate中的session類)來操作這些POJO(譬如保存、獲取及查找)。
EJB 3.0建立在 Hibernate和TopLink的思想和成功這一基礎上。它為Java EE提供了標準的POJO ORM框架。另外,較之現有的POJO持久性解決方案,EJB 3.0有兩項重要創新:
● EJB 3.0讓開發人員可以直接在POJO代碼中注釋映射信息,而不是使用XML文件來指定ORM元數據。譬如說,你可以用注釋來指定與每個JavaBean屬性相對應的關系列名。讀者會在本文后面看到更多的示例。注釋使得映射更直觀,也更輕易維護。
● EJB 3.0為實體bean定義了新的存檔格式。每個存檔定義了持久性上下文,后端數據庫和ORM行為各使用獨立的一組配置。本文會在后面討論持久性上下文。
現在,我們不妨通過幾個簡單的示例來看一下EJB 3.0是如何實現POJO ORM的。
映射簡單對象
在EJB 3.0中,每個實體bean都是JavaBean樣式的簡單類。為了告訴EJB 3.0容器這個類應當進行映象以實現持久性,應當用@Entity來注釋這個類。
每個實體bean類映射到關系數據庫表。默認情況下,表名與類名相對應。可以使用@Table注釋,為該類指定另一個表名。bean類的每個JavaBean屬性映射到表中的列。默認情況下,列名就是屬性名。可以通過為屬性的設置方法添加@Column注釋,來改變這種默認關系。下面是EJB 3.0實體bean類的簡單示例:
@Entity
// @Table (name="AlternativeTableName")
public class Person implements Serializable {
PRotected int id;
protected String name;
protected Date dateOfBirth;
public void setId (int id) {
this.id = id; }
@Id(generate = GeneratorType.AUTO)
public int getId () {
return id; }
public void setName (String name) {
this.name = name; }
// @Column (name="AlternativeColumnName")
public String getName () {
return name; }
public void setDateOfBirth (Date dateOfBirth) {
this.dateOfBirth = dateOfBirth; }
public Date getDateOfBirth () {
新聞熱點
疑難解答