介紹 當(dāng)需要為軟件系統(tǒng)系統(tǒng)提供一種可靠,靈活而又高效的對象持久化方法時(shí),,當(dāng)今的設(shè)計(jì)師和架構(gòu)師們面臨著眾多的選擇,。從技術(shù)的層面上,,這個(gè)選擇往往介于完全面 向?qū)ο?,對象關(guān)系混合,完全關(guān)系化和建立在公開或?qū)S形募袷缴系某R?guī)解決方案之間(如:XML,,OLE的結(jié)構(gòu)化存儲),。從提供者的層面 上,Oracle,, IBM,, Microsoft, POET 和其它的公司提供了相似,,但是彼此間往往不相容的解決方案,。 本文僅論述這些選擇中的一種,即在完全關(guān)系數(shù)據(jù)庫上層面向?qū)ο蟮念惸P瓦M(jìn)行分層,。這并不表明它是唯一,、最好而又簡單的解決方案,但是從實(shí)用的角度看,,它是最常用的一種類型,,卻也是最容易被用錯(cuò)的一種。 我們先快速瀏覽兩個(gè)設(shè)計(jì)領(lǐng)域的模型,,并試圖把它們連接起來:第一,,介紹用UML表達(dá)面向?qū)ο蟮念惸P停坏诙?,關(guān)系數(shù)據(jù)庫模型,。 對每一個(gè)領(lǐng)域我們只涉及影響到我們?nèi)蝿?wù)的主要功能。然后我們將關(guān)注從類模型到數(shù)據(jù)庫模型映射的技術(shù)和問題,,包括對象持久性,,對象行為,,對象和對象標(biāo)識之間 的關(guān)系,。我們將總結(jié)對UML數(shù)據(jù)profile的回顧(Rational Software 推薦),。一些面向?qū)ο笤O(shè)計(jì),UML和關(guān)系數(shù)據(jù)庫建模的相似性也會被提及,。 類模型是UML用來表達(dá)軟件系統(tǒng)邏輯結(jié)構(gòu)的主要工件,。 它用來記錄數(shù)據(jù)需求和模型領(lǐng)域內(nèi)對象的行為。本文不討論創(chuàng)建和詳細(xì)描述該模型的技術(shù),我們將假設(shè)已經(jīng)存在一個(gè)設(shè)計(jì)好的類模型,,它需要映射到關(guān)系數(shù)據(jù)庫上,。
類模型
行為
關(guān)系和特性
聚合是關(guān)聯(lián)的一種形式,,表示一個(gè)類多個(gè)對象的集合在另一個(gè)類中,。復(fù)合是一種更強(qiáng)的聚合形式,說明一個(gè)對象實(shí)際上由其它對象構(gòu)成,。對于關(guān)聯(lián)關(guān)系來說,,它意味 著一個(gè)復(fù)雜的類屬性,,將該屬性映射到關(guān)系模型時(shí)需要更詳細(xì)的考慮,。當(dāng)一個(gè)類表示為生成許多對象實(shí)例的模板或模型時(shí),對象需要在運(yùn)行時(shí)有識別自己的方式,這 樣被關(guān)聯(lián)對象可以對正確的對象實(shí)例施加作用,。在編程語言中,,如C++,對象指針可能會傳遞,,并使所指對象可以訪問一個(gè)獨(dú)一無二的對象實(shí)例,。通常盡管一個(gè)對 象會被銷毀,但是在需要時(shí),,又象上一次有效實(shí)例期間那樣被重建,。所以,這些對象需要一個(gè)存儲機(jī)制來保留它們的內(nèi)部狀態(tài)和關(guān)聯(lián),,并在需要時(shí)恢復(fù)所需狀態(tài),。 繼承給類模型提供一種方式,該方式提取通用行為到泛化的類中,,使這個(gè)泛化類稍后可以做為在一般主題上諸多變異的原形,。繼承是一種管理重用和復(fù)雜性程度的方 式。如我們將看到的,,關(guān)系模型并沒有與繼承關(guān)系的直接對應(yīng)項(xiàng),,這給數(shù)據(jù)模型建立者建立一個(gè)從對象模型到關(guān)系框架造成了困難。從一個(gè)運(yùn)行時(shí)的對象到另外一個(gè) 對象的導(dǎo)航是建立在完全引用的基礎(chǔ)之上,。一個(gè)對象有多種形式的連接(指針或唯一的對象標(biāo)識),,用這些連接可以定位和重建所需的對象。
關(guān)系模型 表和列:一個(gè)關(guān)系表是一個(gè)或多個(gè)列的集合,,每個(gè)列在表結(jié)構(gòu)中有一個(gè)唯一名稱,,并且被定義成一個(gè)特定基本數(shù)據(jù)類型,如:數(shù)字,、文本,、二元數(shù)據(jù)。表定義是一個(gè) 模板,,表的“行”從這個(gè)模板中被創(chuàng)建,,行可能做為一個(gè)表實(shí)例的實(shí)例。關(guān)系模型僅僅提供一個(gè)公共數(shù)據(jù)訪問的模型,。所有數(shù)據(jù)向外對任何一個(gè)過程開放,,以便于被 更新,,查詢和操控。信息隱蔽(information hiding)是未知的,。
行為
關(guān)系和識別
小節(jié)
對象模型中有豐富的關(guān)系集合:繼承,,聚合,,關(guān)聯(lián),復(fù)合,,依賴,,以及其它。在關(guān)系模型中,,可以僅使用外鍵來指明一種關(guān)系,。我們已經(jīng)對感興趣的兩個(gè)領(lǐng)域進(jìn)行了介紹并比較了每一個(gè)領(lǐng)域的幾個(gè)重要功能,然后將簡單了解UML中關(guān)系數(shù)據(jù)模型的標(biāo)注,。
UML數(shù)據(jù)模型Profile(特性描述) 表和列 表在UML數(shù)據(jù)Profile中是帶《Table》構(gòu)造型的類,它在右上角顯示一個(gè)表的符號,。數(shù)據(jù)庫中的列用《Table》類的屬性來建模,。
例如:上面圖型顯示與客戶表關(guān)聯(lián)的屬性。在此示例中,,對象ID被定義為表的主鍵,,還有兩個(gè)列:“Name”和“Address”。注意上圖例子中列的數(shù)據(jù)類型是按照原DBMS的數(shù)據(jù)類型定義的,。 行為 到目前為止,,我們僅定義了表的邏輯(靜態(tài))結(jié)構(gòu)。此外,,我們將描述與列關(guān)聯(lián)的行為,,包括:索引,,鍵,觸發(fā)器,,過程等等,。行為表示為帶構(gòu)造型的操作。 下圖顯示我們討論的表,,它有一個(gè)主鍵約束和索引,,均被定義為帶構(gòu)造型的操作。
注意:“OID”列上的PK標(biāo)簽定義了邏輯主鍵,,而構(gòu)造型操作“?PK? idx_customer00”定義了與主鍵實(shí)現(xiàn)相關(guān)聯(lián)的約束和行為(即主鍵的行為),。 對上例進(jìn)行增加,我們現(xiàn)在可以定義附加行為,,如:觸發(fā)器,,約束,存儲過程,。見下圖:
這個(gè)例子描述了下列行為:
使用上面提供的標(biāo)注,,我們可以在DBMS層次上,對復(fù)雜的數(shù)據(jù)結(jié)構(gòu)和行為建模,。另外,,UML還提供表達(dá)邏輯實(shí)體間關(guān)系的標(biāo)注。
關(guān)系
物理模型
一個(gè)組件表示了一個(gè)離散,,可部署的實(shí)體。在物理模型中,,組件可以映射到一個(gè)物理硬件(UML的節(jié)點(diǎn)),。對于數(shù)據(jù)庫內(nèi)的關(guān)系模式,我們用帶《Schema》 構(gòu)造型的包來表示,。一個(gè)表可以放置到《Schema》中來建立它在數(shù)據(jù)庫中的范圍和位置,。
從類模型到關(guān)系模型的映射
1. 類的建模
2. 標(biāo)識持久對象
3. 假設(shè)每一個(gè)持久類映射到一個(gè)關(guān)系表
4. 選擇一個(gè)繼承策略.
對每一種方法,,我們有對應(yīng)的案例,。但是我們推薦第三種方法,因?yàn)樗詈唵?,最容易維護(hù)和最不容易出錯(cuò),。第一種方法提供了運(yùn)行時(shí)最佳的性能,。第二種方法是第 一種與第三種的折衷。第一種方法展開層次結(jié)構(gòu),,在一個(gè)表里放置所有的屬性,,這樣方便類層次結(jié)構(gòu)中對類的更新和提取,但是不易于驗(yàn)證和維護(hù),。與“行”關(guān)聯(lián)的 業(yè)務(wù)規(guī)則是難以實(shí)現(xiàn)的,,因?yàn)楸碇械拿恳恍卸伎赡鼙粚?shí)例化為層次結(jié)構(gòu)中的對象,。“列”之間的依賴關(guān)系可能變得相當(dāng)復(fù)雜。此外,,對層次結(jié)構(gòu)中任何一個(gè)類的更新 將可能影響層次結(jié)構(gòu)中其它每個(gè)類,,如表中的列被添加,刪除和修改,。 第二種方法是一種折衷方案,,提供了更好的封裝和消除空列??墒?,對父類的修改可能需要在所有子類的表中進(jìn)行復(fù)制,更糟的是,,有兩個(gè)或多個(gè)子類的父類數(shù)據(jù)可 能被冗余地存儲在許多表中,;如果父類的屬性被修改,那么要花相當(dāng)?shù)臅r(shí)間去查找相關(guān)的子表,,并更新受影響的行,。 第三種方法精確地反映了對象模型,它將層次結(jié)構(gòu)中的每一個(gè)類映射成一個(gè)獨(dú)立的表,。父類或子類的更新是在正確空間的局部范圍內(nèi)進(jìn)行的,。對實(shí)體的任何修改被嚴(yán) 格限定于單個(gè)表內(nèi),,因此表的維護(hù)也就相對簡單,。缺點(diǎn)是需要在運(yùn)行時(shí)重構(gòu)結(jié)構(gòu)層次,來精確產(chǎn)生一個(gè)子類的狀態(tài),。一個(gè)“Child”的對象可能需要一個(gè) “Person”的成員變量用于表示它的父輩,。由于這兩者都需要加載,兩次調(diào)用數(shù)據(jù)庫來初始化一個(gè)對象,。隨著類結(jié)構(gòu)層次加深,,初始化或更新一個(gè)單獨(dú)對象的 數(shù)據(jù)庫調(diào)用次數(shù)也隨之增加。 當(dāng)你映射繼承關(guān)系到關(guān)系模型時(shí),,理解上述要點(diǎn)是很重要的,,這樣你就選擇最適合你的方案。
5. 為每一個(gè)類添加一個(gè)唯一的對象標(biāo)識符 系統(tǒng)級別OID的一個(gè)例子可以是一個(gè)使用微軟“guidgen”工具創(chuàng)建的GUID(全局唯一標(biāo)識符),,如{A1A68E8E-CD92-420b- BDA7-118F847B71EB}。類級別的OID可以用簡單得數(shù)字實(shí)現(xiàn)(如:32位計(jì)數(shù)器),。如果一個(gè)對象具有對其它對象的引用,,它可以采用使用它 們的OID的方法。那么,,在運(yùn)行時(shí)有效地將引用的對象從存儲區(qū)加載到模型中,。關(guān)于上述OID值的重點(diǎn)是它沒有超出定義它為標(biāo)識符的簡單含義。它們僅是邏輯 指針而沒有其它意義,。在關(guān)系模型中,,情況往往是不同的。 關(guān)系模型中標(biāo)識正常地用一個(gè)主鍵實(shí)現(xiàn),。主鍵是一個(gè)表中的一組“列”,,它們合起來可以唯一地標(biāo)識一個(gè)行。例如:名稱和地址可以唯一地標(biāo)識一個(gè)“客戶”,。其它 實(shí)體,,如:“銷售員”引用“客戶”,它們要實(shí)現(xiàn)基于“客戶”主鍵的外鍵,。這個(gè)方法存在的問題是:將業(yè)務(wù)信息(如客戶名和地址)嵌入標(biāo)識符中對我們目標(biāo)的影 響,。設(shè)想三個(gè)或四個(gè)表全部具有基于“客戶”主鍵的外鍵,對于一個(gè)需要修改客戶主鍵(如:增加一個(gè)用戶類型)的系統(tǒng)修改,,那么既要修改客戶表,,也要修改與外 鍵相關(guān)的實(shí)體,這個(gè)工作是十分巨大的,。 另一方面,,如果一個(gè)OID被當(dāng)作主鍵實(shí)現(xiàn),并為其它表建立外鍵,,那么修改范圍僅限于主表,,并且修改的影響也因此大大減小。實(shí)際上,,一個(gè)基于業(yè)務(wù)數(shù)據(jù)的主鍵 也許會被修改,。如:一個(gè)客戶可以修改地址和名字,既然這樣,,這個(gè)變化需要被正確的傳遞到所有其它相關(guān)的實(shí)體,,更不用提改變部分主鍵信息的困難,。 一個(gè)OID總是引用同一個(gè)實(shí)體,而不管其它信息怎么改變,。在上面的例子中,,客戶可以修改名稱和地址,與它相關(guān)聯(lián)的表不需要被修改,。當(dāng)把對象模型映射到關(guān)系 表時(shí),,實(shí)現(xiàn)完全OID的標(biāo)識符比采用業(yè)務(wù)聯(lián)系的主鍵更加便捷。用OID做為主鍵和外鍵的方法將為對象提供更好的加載和更新效率,,將維護(hù)服務(wù)減到最少,。實(shí)際 上,一個(gè)與業(yè)務(wù)相聯(lián)系的主鍵可以替換為:
再次重申,,是使用有意義的鍵還是使用OID取決于被開發(fā)系統(tǒng)的實(shí)際需要,。
6. 映射屬性到“列” 對復(fù)雜屬性(即屬性為其它對象)使用下面詳細(xì)的步驟來處理關(guān)聯(lián)和聚合關(guān)系,。
7. 映射關(guān)聯(lián)到外鍵
8. 映射聚合和復(fù)合 弱聚合的第二個(gè)例子是:一個(gè)實(shí)體在那里使用或排除了另一個(gè)實(shí)體的所有權(quán),。例如:一個(gè)“人”的實(shí)體擁有一組股票,這標(biāo)明這個(gè)人可能與一個(gè)“股票”表中的某些 股票有關(guān)聯(lián),,也可能沒有關(guān)系,。但是每個(gè)股票可以聯(lián)系一個(gè)人,或不與任何人發(fā)生關(guān)系,。如果這個(gè)人不在了,,這個(gè)股票將變?yōu)椤盁o主”的,或者被傳遞給下一個(gè)人,。 在這個(gè)關(guān)系模型中,,可以通過每個(gè)股票有一個(gè)“所有者”列來實(shí)現(xiàn),這個(gè)“所有者”列將存儲一個(gè)人的標(biāo)識符(OID),。 強(qiáng)聚合形式則有與之關(guān)聯(lián)的完整約束,。復(fù)合表明一個(gè)實(shí)體由部件組成,并且這些部件對整體有依賴關(guān)系,。例如:一個(gè)人可以有很多證明文件,,如護(hù)照,出生證明,,駕 照等,。這個(gè)人的實(shí)體可以由這樣的一組文件組成。如果這個(gè)人從系統(tǒng)里被刪除,,那么證明文件也要被刪除,,因?yàn)檫@些文件被映射到一個(gè)唯一個(gè)體。 如果我們暫時(shí)忽略O(shè)ID,,弱聚合可能使用中間表來實(shí)現(xiàn)(對多對多的情況)或者在一個(gè)聚合的類或表采用一個(gè)外鍵來實(shí)現(xiàn)(一對多的情況),。在多對多關(guān)系的情況 下,,如果父類被刪除,中間表中的實(shí)體也要被刪除,。在一對多的情況下,,如果父類被刪除,外鍵輸入(如“所有者”)必須被清除,。 在復(fù)合的情況下,,外鍵的使用是強(qiáng)制的,約束條件是父類刪除后,,部件也必須被刪除,。邏輯上,復(fù)合是有一種含義,,部件主鍵形成了全部主鍵的一部分,。例如:一個(gè)人的主鍵由他證明文件組成。盡管實(shí)際上是相當(dāng)冗長的,,但邏輯關(guān)系上為真,。
9. 定義關(guān)系作用
10. 模型行為
不同數(shù)據(jù)庫商的關(guān)系數(shù)據(jù)庫通常包含不同形式的,,基于SQL的可編程腳本語言,用來實(shí)現(xiàn)對數(shù)據(jù)的操作,。最常用的例子 是觸發(fā)器和存儲過程,。當(dāng)我們混合對象和關(guān)系模型,要做的決定往往是:是實(shí)現(xiàn)類模型中所有的業(yè)務(wù)邏輯,,還是將部分的業(yè)務(wù)邏輯放在關(guān)系DBMS中更常用而有效 率的觸發(fā)器和存儲過程中,。從完全面向?qū)ο蟮慕嵌瓤?,答案是避免使用觸發(fā)器和存儲過程,并且將所有行為放到類中,。這樣會使行為局部化,,從而提供了一個(gè)更清晰 的設(shè)計(jì),簡化了維護(hù),,并且提供了在不同DBMS提供商之間更好的移植性,。 在現(xiàn)實(shí)世界,存儲過程和觸發(fā)器的設(shè)計(jì)目標(biāo)底線可以是每秒至少執(zhí)行幾百次或幾千次之多,。如果為了追求模型的清晰,,移植性,可維護(hù)性和靈活性,,那么就將所有的行為放在對象方法中,。
如果性能是關(guān)注的焦點(diǎn),可以考慮將部分行為交給更有效的DBMS編程語言,。注意到將對象模型與存儲過程以安全方式集成所花的額外時(shí)間,,包括遠(yuǎn)程影響和調(diào)試的問題,可能要比簡單部署更高性能的硬件更多,。 如前面所述,,UML數(shù)據(jù)profile提供下列擴(kuò)展(構(gòu)造型操作),可用來對DBMS行為建模:
11. 產(chǎn)生物理模型
總結(jié) |
|