歡迎您光臨本站 註冊首頁

使用 JPA 和 Hibernate 實現組合鍵

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
如今,面向對象映射(ORM)工具在全球得到了廣泛應用和部署,您通常不必為組合鍵這樣的難題絞盡腦汁。一般情況下,設計鍵時可選擇簡單的整數,放心地將問題留給工具處理。但有時會遇到一些特殊的情況,需要使用組合鍵,此時就需要一種相應的戰略。本文介紹的技巧使您能夠使用 JPA 和 Hibernate 實現組合鍵。

問題定義

本技巧從問題的簡單的描述開始:定義組合資料庫鍵。這個鍵組合了多列,唯一地定義一個資料庫表的行。有時,組合鍵也稱為自然鍵 或業務鍵。某些時候使用組合鍵的原因是所選鍵在某些方面與最終用戶的業務領域相關聯。要定義組合鍵,只需從該領域中選擇一些屬性,並將其組合在一起,提供所需的行唯一性程度。組合鍵的缺點是設計和編碼略有難度。此外,組合鍵傾向於將您的資料庫和 ORM 設計綁定到原始領域。後者可能會成為嚴重的問題。





實體代碼

清單 1 展示了一個名為 BillingAddress 的 Java 類。該類建模一名個人或一個組織的賬單郵寄地址。賬單本身與另一個名為 PurchaseOrder 的 Java 類關聯。這裡並沒有什麼出人意料之處 — 下置購買訂單,接下來進行賬單郵寄流程。


清單 1. BillingAddress 類
				  import javax.persistence.*;  import java.io.Serializable;    @Embeddable  public class BillingAddress implements Serializable {        private String street;      private String city;        BillingAddress() {}        public BillingAddress(String street, String city) {          this.street = street;          this.city = city;      }        public String getStreet() {          return street;      }        private void setStreet(String street) {          this.street = street;      }        public String getCity() {          return city;      }        private void setCity(String city) {          this.city = city;      }  }

這裡有必要說明一個要點,該類實現了 Java Serializable 介面。另外還要注意帶有註釋 @Embeddable 的一行。此註釋是組合鍵拼圖中的第一塊。帶有 @Embeddable 註釋的 Java 類本身可作為其他類的子組件。這聽起來似乎有點複雜,而實際並非如此。作為演示,清單 2 展示了 PurchaseOrder 類,它使用清單 1 中的 BillingAddress 類。


清單 2. PurchaseOrder 類
				  import javax.persistence.*;    @Entity  @Table(name = "PURCHASE_ORDERS")  @IdClass(BillingAddress.class)  public class PurchaseOrder {    	PurchaseOrder() {}    	PurchaseOrder(BillingAddress billingAddress) {  	street = billingAddress.getStreet();  	city = billingAddress.getCity();  	}    	@Id  	@AttributeOverrides({  	@AttributeOverride(name = "street",  	column = @Column(name="STREET")),  	@AttributeOverride(name = "city",  	column = @Column(name="CITY"))  	})    	private String street;  	private String city;  	private String itemName;    	public String getItemName() {  	return itemName;  	}    	public void setItemName(String itemName) {  	this.itemName = itemName;  	}  }

註釋總是有些難以理解,清單 2 也不例外。因此,我會將其拆分成便於管理的塊。第一個註釋是 @Entity,指明該類是一個資料庫實體(也就是說,它將構成 ORM 解決方案的一部分)。通常,看到 @Entity 註釋就等於看到了對應的資料庫表。後者由清單 2 中名為 @Table 的相應註釋表明。我發現,以這種方式拆分程序更容易理解。

清單 2 中的下一個註釋是 @IdClass,它定義組合鍵類引用。您可能已經注意到了,該類引用清單 1 中的 BillingAddress 類。跳過清單 2 中的構造方法,注意 @Id 註釋。組合鍵就是在這裡使用嵌套 @AttributeOverrides 註釋定義的。這些註釋用於定義組合鍵列:分別是 “STREET” 和 “CITY”。

就在清單 2 的註釋之後,您是否看到了來自清單 1 的兩行重複的代碼?當然,重複的代碼是表示街道和城市的兩個私有數據成員。這樣的重複是創建組合鍵所必需的。





資料庫模式

至此討論的內容都是技術層面上的。現在我們將以更加具體的方式表述此技巧,我們將生成一個資料庫模式。清單 3 展示了來自這個非常簡單的 ORM 資料庫設計的模式。


清單 3. 資料庫模式
				  drop table PURCHASE_ORDERS if exists;    create table PURCHASE_ORDERS (          street varchar(255) not null,          city varchar(255) not null,          itemName varchar(255),          primary key (street, city)  );  

可以看到,主鍵實際上是由 street 和 city 欄位組合而成的。在真實的資料庫中 — 例如,帶有圖形用戶界面(GUI)工具的資料庫中,這將得到怎樣的效果?在給出答案之前,我編寫了一段簡單的客戶端代碼,用於將一個或兩個實體保持到資料庫中。

清單 4 展示了一段代碼摘錄,實例化上文所定義類的對象。


清單 4. ORM 客戶端代碼摘錄
				          // Start EntityManagerFactory          EntityManagerFactory emf =                  Persistence.createEntityManagerFactory("helloworld");            // First unit of work          EntityManager em = emf.createEntityManager();          EntityTransaction tx = em.getTransaction();          tx.begin();            PurchaseOrder purchaseOrder =             new PurchaseOrder(new BillingAddress("Broad Street", "Boston"));          purchaseOrder.setItemName("My new computer");          em.persist(purchaseOrder);            tx.commit();          em.close();  

清單 4 中的代碼展示了從 PurchaseOrder 對象的實例化和設置一直到此對象在資料庫中的持久化這個完整的過程。這實實在在地體現了 ORM 的魔力。讓我們來看看發生了什麼。

首先創建一個 EntityManagerFactory 的實例,隨後使用此實例創建 EntityManager 的一個名為 em 的實例。後者隨後用於將 PurchaseOrder 對象實例寫入資料庫。保持到資料庫中的實際過程是在事務中完成的。

事務就是一組原子操作,可能全部成功完成,或在出現錯誤時回滾。如清單 4 所示,EntityManager 對象用於創建 EntityTransaction 的一個名為 tx 的實例。後面這個對象將工作單元打包到事務中。

請注意對 persist() 和 commit() 的調用。必須牢記,除非同時出現這兩個調用,否則不能更改資料庫。這是 Java 持久 API(JPA)的簡單模式。

為了完成 ORM 之旅,圖 1 展示了運行清單 4 中的代碼之後資料庫的狀態。代碼是使用稱為 HSQLDB 的內存資料庫測試的,這種產品包含一個簡單的 GUI 工具。圖 1 顯示了 HSQLDB 資料庫的狀態。可以看到,我對 PURCHASE_ORDERS 表運行了 SQL 查詢。該表是通過模式創建的,模式本身是使用本文前面給出的清單創建的。


圖 1. 填充后的資料庫


在圖 1 中,可以看到清單 4 中的這行代碼產生的效果:purchaseOrder.setItemName("My new computer")。對 setter 代碼的調用使用 String 數據 “My new computer” 填充了資料庫行中的相關列。就工作流而言,可認為整個程序都是在創建新計算機的購買訂單時運行的,隨後就是發票郵寄過程。工作流中的所有步驟都隱式地存儲在資料庫中。





結束語

清單 1 和清單 2 中定義的組合鍵允許您將多個列綁定在一起。列的組合能提供所需的唯一性,使您的資料庫表中能擁有任意數量的行。我們已經介紹了如何實現這一目標。現在,您需要大致了解為什麼要選擇這種有些奇特的資料庫設計方法。

使用組合鍵的最常見的原因或許就是為了向後兼容。換句話說,在您需要將新資料庫代碼整合到遺留環境中的時候。我認為,如今故意以這樣一種方式設計資料庫的做法並不常見,您只需要在符合慣例的場合創建組合鍵。

在這種情況下,我認為對於這種方法的討論都是毫無意義的。如果組合鍵是標準,那麼就不可能很快發生變化。在很多時候,都有大量現有數據是使用這種方法構造的。因而,如果組合鍵被數字鍵所取代,那麼遺留數據就必須進行遷移。此外,也有許多業務流程是對應組合鍵數據的。所有這些因素結合在一起,使組合鍵成為一種必不可少的技術。(責任編輯:A6)



[火星人 ] 使用 JPA 和 Hibernate 實現組合鍵已經有560次圍觀

http://coctec.com/docs/linux/show-post-68741.html