程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用JPA和Hibernate實現組合鍵

使用JPA和Hibernate實現組合鍵

編輯:關於JAVA

問題定義

本技巧從問題的簡單的描述開始:定義組合數據庫鍵。這個鍵組合了多列,唯一地定義一個數據庫表的行。有時,組合鍵也稱為自然鍵 或業務鍵。某些時候使用組合鍵的原因是所選鍵在某些方面與最終用戶的業務領域相關聯。要定義組合鍵,只需從該領域中選擇一些屬性,並將其組合在一起,提供所需的行唯一性程度。組合鍵的缺點是設計和編碼略有難度。此外,組合鍵傾向於將您的數據庫和 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 中定義的組合鍵允許您將多個列綁定在一起。列的組合能提供所需的唯一性,使您的數據庫表中能擁有任意數量的行。我們已經介紹了如何實現這一目標。現在,您需要大致了解為什麼要選擇這種有些奇特的數據庫設計方法。

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

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved