概念: 關聯式資料庫與物件導向
本概念論述物件模型和關聯式資料模型的概觀,也包含持續性架構的摘要說明。
關係
主要說明

簡介

本概念文件論述物件模型和關聯式資料模型的概觀,也包含持續性架構的摘要說明。

關聯式資料庫與物件導向

關聯式資料庫和物件導向不是完全相容的觀念。分別代表兩種不同的領域觀點:在 RDBMS 中,只有資料;在「物件導向」系統中,只有行為。沒有誰優誰劣:物件導向模型適用於不注重資料且具有複雜行為和特殊狀態行為的系統,或按照自然界階級逐步存取資料的系統(例如,材料清單)。RDBMS 模型適用於報表應用程式和具有動態或特殊關係的系統。

實際上,許多資訊都已儲存在關聯式資料庫中,如果物件導向應用程式想要存取資料,則必須能夠讀寫 RDBMS。此外,物件導向系統通常還需要與非物件導向系統共用資料。因此,很自然就會以 RDBMS 做為共用機制。

雖然物件導向和關聯式設計有一些共同的特性(在觀念上,物件屬性就像實體直欄),但本質上的差異仍然不易順利整合。本質上的差異在於資料模型會公開資料(經由直欄值),而物件模型會隱藏資料(封裝在公用介面背後)。

關聯式資料模型

關聯式模型由實體和關係組成。實體可能是實體表格或多個表格的邏輯投射,又稱為概略表。下圖顯示 LINEITEM、ORDER 和 PRODUCT 表格,以及三者之間的各種關係。關聯式模型具有下列元素:

圖解說明詳見下文。

關聯式模型

實體含有直欄。每一個直欄以名稱和類型來定義。在上圖,LINEITEM 實體有 LineItem_Id(主鍵)、Description、Price、Quantity、Product_Id 及 Order_Id 直欄 (最後兩個是外來鍵,將 LINEITEM 實體連結至 ORDER 和 PRODUCT 實體)。

實體含有記錄或列。每一列代表一組獨特的資訊,這組資訊通常代表物件的持續資料。 

每一個實體有一或多個主鍵。LineItem_Id 是 LINEITEM 的主要索引鍵。

關係的支援由廠商自行決定。範例中顯示 PRODUCT 和 LINEITEM 表格之間的邏輯模型和關係。在實體模型中,通常以主鍵/主鍵參照來實作關係。如果一個實體與另一個實體有關係,則一定含有外來鍵直欄。外來鍵直欄包含的資料可將實體中的特定記錄與相關實體建立關係。

關係具有多重性(又稱為基數)。常見的基數包括一對一 (1:1)、一對多 (1:m)、多對一 (m:1)、多對多 (m:n)。在範例中,LINEITEM 與 PRODUCT 具有 1:1 的關係,PRODUCT 與 LINEITEM 具有 0:m 的關係。

物件模型

特別值得一提,物件模型包含類別(如需物件模型的完整定義,請參閱 [UML01])。類別定義一組物件(有時稱為物件實例)的結構和行為。結構以屬性(資料值)和關聯(類別之間的關係)來表示。下圖展示一個簡單的類別圖,其中只顯示類別的屬性(資料)。

圖解說明詳見下文。

物件模型(類別圖)

一個「訂單」有一個編號(訂單號碼)和對於 1 或多個 (1..*)「商品細目」的一個關聯。每一個「商品細目」有一個數量(訂購數量)。

物件模型支援繼承。一個類別可以繼承另一個類別的資料和行為(例如,SoftwareProduct 和 HardwareProduct 產品繼承 Product 類別的屬性和方法)。

持續性架構

大多數商業應用系統都以關聯式技術做為實體資料儲存庫。物件導向應用程式開發人員面對的挑戰就是充分區隔和封裝關聯式資料庫,不讓資料模型的變更「破壞」物件模型,反之亦然。已有許多解決方案可讓應用程式直接存取關聯式資料;主要的問題在於如何完美地整合物件模型和資料模型。

資料庫應用程式設計介面 (API) 開始已出現標準的規格(例如 Microsoft 的「開放資料庫連接」API 或 ODBC),但都有專利權(內建在特定資料庫中)。這些 API 提供資料操作語言 (DML) 穿透服務,可讓應用程式存取原始關聯式資料。在物件導向應用程式中,資料必須經過物件關聯式轉換,才能供應用程式取用。這需要大量的應用程式碼將原始資料庫 API 結果轉換成應用程式物件。物件關聯式架構的目的是分類封裝實體資料儲存庫,並提供適當的物件轉換服務。

圖解說明詳見下文。

持續性架構的用途

在物件導向應用程式中,應用程式開發人員會付出 30% 以上的時間來實作關聯式資料庫存取。如果未正確實作物件關聯式介面,投資心血將付諸流水。實作物件關聯式架構可以穩住這項投資。物件關聯式架構可重複運用在以後的應用程式中,讓物件關聯式實作成本降至總實作成本的 10% 以下。實作任何系統時,維護工作是首要的成本考量。在一個系統的整個生命週期內,維護工作就佔總成本的 60% 以上。實作不良的物件關聯式系統,不論在技術維護或財務管控上,將註定是一場可怕的夢魘。

物件關聯式架構的主要特性

  • 效能。將物件拆解成資料或將資料組合成物件時,一定要格外謹慎。在資料傳輸量很高且負荷嚴重的系統中,這通常成為存取層設計不良的致命傷。
  • 降低設計危害。調整物件模型以利儲存至關聯式系統,以及變更關聯式模型以利於儲存物件,應該是曾經以關聯式資料庫來建置系統的物件技術人員都很熟悉的一種型樣。雖然通常要稍微調整,但設計良好的存取層確實可避免物件和關聯式模型設計退化。
  • 延展性。存取層是一種白箱架構,一旦架構需要加入某些功能,應用程式開發人員將可延伸架構。存取層通常可滿足(不必延伸)應用程式 65-85% 的資料儲存需求。如果存取層未設計成可延伸的架構,則想要滿足應用程式最後 35-15% 的資料儲存需求,將相當困難又耗費成本。
  • 說明文件。存取層是黑箱元件,也是白箱架構。黑箱元件的 API 必須明確定義、清楚記錄且容易理解。如稍早所述,存取層是可延伸的設計。可延伸的架構必須完整詳實的記載。必須指出可衍生子類別的類別。必須對每一個相關類別的互動規則指定特性(例如,public、private、protected、final 等). 再者,存取層架構的大量設計必須公開且詳細記錄,才能提高延展性。
  • 支援共通的物件關聯式對映。存取層應該支援一些基本的物件關聯式對映,不需要再延伸。本文後續章節將進一步討論這些物件關聯式對映。
  • 持續性介面:在物件導向應用程式中,物件應用程式的商業模型可擷取問題領域的語意知識。開發人員應該可輕易操作物件及進行物件互動,不必太擔心資料儲存和擷取細節。應該提供一部份定義明確的持續性介面(儲存、刪除、尋找)給應用程式開發人員。

共通的物件關聯式服務

物件關聯式應用程式已開始浮現出共通的型樣。不斷跨越鴻溝的 IT 專家開始發現到成功的物件關聯式應用程式都有某些共同的結構和行為。高階的 CORBA 服務規格已正式納入這些結構和行為(同樣適用於 COM/DCOM 系統)。

適用於物件關聯式對映的 CORBA 服務規格如下:

下列章節按照這些種類,依序討論共通的物件關聯式服務。建議讀者參考適當的 CORBA 規格,取得進一步的詳細資料。

持續性

「持續性」說明物件如何利用次要儲存媒體,在跨越不連續的階段作業時,仍然可以保存狀態。持續性可讓使用者在一個階段作業中儲存物件,然後在後續的階段作業中取回物件。後來存取物件時,屆時的狀態(例如屬性)與前一個階段作業中的狀態完全相同。在多使用者的系統中,可能並非如此,因為其他使用者可能存取和修改相同的物件。持續性與本節討論的其他服務有關。此在刻意安排討論關係、並行性及其他主題(與 CORBA 的服務分解一致)。

以下例子說明持續性提供的特定服務:

  • 資料來源連線管理:物件關聯式應用程式一定會起始設定實體資料來源的連線。關聯式資料庫系統通常需要伺服器和資料庫的識別。連線管理的特性通常隨資料庫供應商而定,因此必須以靈活的方式來適當地設計架構。
  • 物件擷取:從資料庫還原物件時,資料會從資料庫擷取出來並轉換成物件。這一道流程包括從資料來源擷取的資料庫特定結構中取出資料、將資料從資料庫類型重新編排成適當的物件類型及/或類別、建立適當的物件,以及設定特定的物件屬性。
  • 物件儲存:物件儲存的流程就是物件擷取的反向操作流程。 其中會從物件中擷取適當屬性的值、以屬性值建立資料庫特定結構(可能是 SQL 字串、儲存程序或特殊的遠端程序呼叫),然後將結構送往資料庫。
  • 物件刪除:在系統內刪除的物件,必須從關聯式資料庫中刪除相關資料。刪除物件需要從物件中擷取適當的資訊、建構刪除要求(可能是 SQL 字串、儲存程序或特殊的遠端程序呼叫),然後向資料庫提出此要求。請注意,某些語言(例如 Smalltalk 和 Java)並不支援明確刪除;而是支援一種稱為記憶體回收的策略。支援這些語言的持續性架構必須提供另一種替代方式,一旦應用程式不再參照資料時,就從資料庫中移除此資料。有一種常見的方法是由資料庫維護一個物件被其他物件參考的次數,稱為 參考計數。當物件的參考計數降到零時,即表示不再被任何物件參考,此時就可能刪除此物件。可能適合將參考計數為零的物件刪除,因為即使物件已不再被參考,但仍有可能被查詢。因此,還是需要一種何時容許刪除物件的整體資料庫原則。

查詢

如果缺少搜尋和擷取特定物件的機制,持續性物件儲存亦無用武之地。查詢機能可讓應用程式根據各種準則來詢問和擷取物件。物件關聯式對映架構提供的基本查詢作業是「尋找」和「尋找唯一的」。根據查詢準則,「尋找唯一的」作業只擷取一個特定的物件,而「尋找」會傳回一群物件。

各種資料儲存庫查詢機能的差別很大。簡單的檔案型資料儲存庫可能實作自創的固定查詢作業,而關聯式系統則提供靈活的資料操作語言。物件關聯式對映架構將關聯式查詢模型延伸成為以物件為主,而非以資料為主。另外也實作穿透機制,以運用關聯式查詢彈性和各廠商特定的延伸機制(例如,儲存程序)。

請注意,以資料庫為基礎的查詢機制和物件典範之間存在一些可能的衝突:資料庫查詢機制由表格中的屬性(直欄)決定。在相對應的物件中,封裝原則可防止我們看到屬性的值;由類別的操作封裝。封裝的理由在於變更應用程式很簡單:只要類別公開的操作不變,我們就可以直接改變類別的內部結構,不必考慮相依類別。以資料庫為基礎的查詢機制依賴類別的內部表示法,事實上會 破壞封裝。架構的主要問題在於如何避免查詢導致應用程式難以變更。

交易

交易式支援可讓應用程式開發人員定義不可分割的工作單位。以資料庫術語來說,這表示系統必須可以對資料庫套用一組變更,不然就必須確定未套用任何變更。一項交易內的操作必須全部執行成功,不然整個交易就算失敗。物件關聯式架構至少應該提供一種類似關聯式資料庫的確定/回復交易機能。在多使用者環境中設計物件關聯式架構,可能會面臨許多挑戰,必須仔細思量。

除了持續性架構提供的機能之外,應用程式也必須瞭解如何處理錯誤。當交易失敗或中止時,系統必須有能力還原為先前穩定的狀態,通常是從資料庫讀取先前的狀態資訊。因此,持續性架構和錯誤處理架構之間有密切的互動關係。

並行性

多使用者物件導向系統必須控制對物件的並行存取。當許多使用者同時存取一個物件時,系統必須提供一種機制,確保以可預測和可控制的方式來修改持續儲存庫中的物件。物件關聯式架構可能實作悲觀及/或樂觀並行控制。

  • 悲觀並行控制規定從資料儲存庫擷取物件時,應用程式開發人員必須指定他們的意圖(例如,唯讀、寫入鎖定等). 如果物件已鎖定,則其他使用者存取此物件時可能暫停執行,必須等待鎖定交出。請小心使用和實作悲觀並行性,因為可能導致死結狀況。
  • 樂觀並行控制認為不太可能同時存取相同物件。當修正儲存到資料庫時會偵測到並行性衝突。通常,如果物件在取出之後已被另一位使用者修改過,則會傳回錯誤給應用程式,指出修改操作失敗。應用程式必須負責偵測和處理錯誤。這需要由架構來快取物件的並行值,然後與資料庫做比較。如果並行性衝突很少,則樂觀並行性的成本較低,但如果衝突數量很高,則成本也會很高(因為發生衝突時必須一切重來)。

使用共用資料的所有應用程式必須採取相同的並行策略;在相同的共用資料中,不能混合樂觀和悲觀並行控制,否則可能毀損。對於一致性並行策略的要求,最好透過持續性架構來處理。

關係

物件之間具有關係。一個「訂單」物件會有許多「商品細目」物件。一個「書籍」物件會有許多「章節」物件。一個「員工」物件只屬於一個「公司」物件。在關聯式系統中,實體之間的關係以外來鍵/主鍵參照來實作。在物件導向系統中,通常透過屬性來明確實作關係。如果 Order 物件有 LineItem,則 Order 將包含 lineItems 屬性。Order 的 lineItems 屬性將包含許多 LineItem 物件。

物件關聯式架構的關係層面和持續性、交易及查詢服務相互依存。在儲存、擷取、交易或查詢一個物件時,必須考慮其相關的物件:

  • 擷取一個物件時,也要擷取相關聯的物件嗎?沒錯,這很單純,但不需要相關聯的物件時,這樣做的成本就很高。理想的架構應該容許存在混合的策略。
  • 儲存一個物件時,如果相關聯的物件已變更,也要一併儲存嗎?同樣地,答案視情況而定。

將共通的物件關聯式架構服務分開考慮,在概念上比較清楚,但其物件關聯式架構實作會共存。不僅在個別的組織之間必須一致地實作服務,在共用相同資料的所有應用程式之間也一樣。架構是達成這個目標的一種最經濟的方法。