UML在關(guān)系型數據庫設計中的應用
1. 介紹
許多人認為面向對象概念和關(guān)系型數據庫相互不一致,并且不能結合。事實(shí)上完全相反!經(jīng)過(guò)靈活的使用,一個(gè)關(guān)系型數據庫能夠為面向對象(OO)模型提供一套優(yōu)秀的實(shí)現。同樣的模型能夠用來(lái)開(kāi)發(fā)編程代碼和關(guān)系型數據庫結構。
關(guān)系型數據庫技術(shù)是意義深遠的、強大的,但它比許多開(kāi)發(fā)商使你相信的要難得多。單個(gè)表是簡(jiǎn)單易懂的、直觀(guān)的。但由數以百計的表組成(這是常見(jiàn)的)的應用要徹底了解是相當困難的。這正是OO模型有用之處。 OO模型使你深入地、連貫地思考問(wèn)題。
OO模型提供一種問(wèn)題的超結構(superstructure)的思考方式,然后該方式能夠用關(guān)系型數據庫的更低層的組成塊來(lái)實(shí)現。
本文章綜合地討論了關(guān)系型數據庫技術(shù),而不是集中于特定的產(chǎn)品上。我們將不討論物理設計細節(例如存儲分配和物理聚集),因為它們是依賴(lài)于產(chǎn)品的。
用關(guān)系型數據庫實(shí)現UML模型有兩個(gè)方面:映射結構(第2節)和映射功能(第3節)。第4節注解了面向對象到關(guān)系型數據庫的擴展。第5節總結本文章。
2. 結構映射到表
UML對象模型在本質(zhì)上只是一個(gè)擴展的實(shí)體-關(guān)系(ER)模型 。使用設計數據庫的ER模型的方式受到普遍接受,而我們以一種近似的但更強大的方式-使用UML對象模型。OO模型的主要優(yōu)勢在于編程和數據庫的相同的模型工作。而且,作為考慮功能性的一種方式(第3節),我們強調OO模型的導航。這一節顯示如何實(shí)現UML對象模型的主要構造。
2.1 標識(identity)
實(shí)現對象模型的第一步是處理標識。我們從定義幾個(gè)術(shù)語(yǔ)開(kāi)始。
1)候選鍵(candidate key)是一個(gè)或多個(gè)屬性的組合,它唯一地確定某個(gè)表里的記錄。一個(gè)候選鍵里的屬性集必須是最小化的;除非破壞唯一性,否則屬性不能從候選鍵刪除。候選鍵里的屬性不能為空。
2)主鍵(primary key)是一個(gè)特定地選定的候選鍵,用來(lái)優(yōu)先地參考記錄。
3)外鍵(foreign key)是一個(gè)候選鍵的參考。外鍵必須包括每個(gè)要素屬性的一個(gè)值,或者它必須全部為空。外鍵用來(lái)實(shí)現關(guān)聯(lián)和一般化。
正常地你應該為每個(gè)表定義一個(gè)主鍵,盡管偶爾有例外。我們強烈建議所有的外鍵都只指向主鍵而不是其它的候選鍵。
定義主鍵有兩種基本的方法:
1)基于存在的標識。你應該為每個(gè)類(lèi)表加一個(gè)對象標識符屬性,并將它設為主鍵。每個(gè)關(guān)聯(lián)表的主鍵包括一個(gè)或更多的相關(guān)類(lèi)的標識符?;诖嬖诘臉俗R符有作為單獨屬性的優(yōu)勢,占位小且大小相同。只要你的關(guān)系型數據庫管理系統(RDBMS)受支持,基于存在的標識符就沒(méi)有性能的劣勢。(多數RDBMS提供有效的基于存在的標識符的分配順序號碼。)唯一的劣勢是基于存在的標識符在維護時(shí)內沒(méi)有固有的意義。
2)基于值的標識。一些真實(shí)世界的屬性的組合確定了每個(gè)對象?;谥档臉俗R有不同的優(yōu)勢。主鍵對于用戶(hù)有固有的意義,容易進(jìn)行調試和數據庫維護。在另一面,基于值的主鍵很難改變。一個(gè)主鍵的改變需要傳播到許多外鍵。一些對象沒(méi)有自然的真實(shí)世界里的標識符。
我們推薦你在超過(guò)30個(gè)類(lèi)的RDBMS應用里使用基于存在的標識?;诖嬖诤突谥档臉俗R都是所有RDBMS應用的可行選項。
2.2 域(屬性類(lèi)型)
屬性類(lèi)型是UML術(shù)語(yǔ),對應于數據庫著(zhù)作里的域的術(shù)語(yǔ)。比起直接用數據類(lèi)型,域提升到更一致的設計,并便利了應用的定位。
簡(jiǎn)單域很容易實(shí)現。你僅僅要定義相應的數據類(lèi)型和大小。并且每個(gè)用了域的屬性,你都必須為每個(gè)域約束加入一條SQL查詢(xún)子句。簡(jiǎn)單域的一些例子是:名字(name),長(cháng)字符(longString)和電話(huà)號碼(phone-Number)。
一個(gè)枚舉域把一個(gè)屬性限制在一系列的值里。枚舉域比簡(jiǎn)單域實(shí)現起來(lái)更復雜,圖表1顯示了四個(gè)方法。
圖表1:枚舉的實(shí)現方法
2.3類(lèi)
正常情況下,我們把每個(gè)類(lèi)映射為一個(gè)表,每個(gè)屬性映射為一個(gè)列。你可能因一個(gè)已產(chǎn)生的標識符(基于存在的標識符)、隱藏的關(guān)聯(lián)(第2.4節)和通用鑒別器(第2.5節)需要一些另外的列。
2.4關(guān)聯(lián)
現在我們討論關(guān)聯(lián)的實(shí)現。我們已經(jīng)把我們的陳述分為建議的映射(我們正常使用的映射),可選的映射(我們偶爾使用的映射)和不鼓勵的映射(我們遇到的應該避免的錯誤)。我們所有的例子都采用基于存在的標識。
2.4.1 建議的映射
多對多關(guān)聯(lián)。用一個(gè)特別的表(圖表2)來(lái)實(shí)現一個(gè)多對多關(guān)聯(lián)。關(guān)聯(lián)的主鍵是每個(gè)類(lèi)的主鍵的合并。那些省略號(...)表示在模型里沒(méi)有顯示出來(lái)的屬性。主鍵用黑體字體顯示。
一對多關(guān)聯(lián)。把一個(gè)外鍵隱藏在“多”表(圖表3)。角色名字成為外鍵屬性名字的一部分。
零或一對一關(guān)聯(lián)。把外鍵隱藏在“零或一”表(圖表4)。
其它一對一關(guān)聯(lián)。把外鍵隱藏在任一表里。
圖表2:建議的實(shí)現:特殊的多對多關(guān)聯(lián)表
圖表3:建議的實(shí)現:隱藏的一對多關(guān)聯(lián)
圖表4:建議的實(shí)現:隱藏的零或一對一關(guān)聯(lián)
可選的映射 正常情況下我們使用建議的映射。但有些偶爾的情況,可選的映射更合適。
特別的表。你也可以用特別的表(圖表5)來(lái)實(shí)現一對多和一對一關(guān)聯(lián)。特別的表給了你更統一的設計和更大的擴展性。無(wú)論如何,特別的關(guān)聯(lián)表打碎了數據庫,并增加了表的數量。此外,特別的關(guān)聯(lián)表不能強迫一個(gè)更低的多重性限度為“一”。
圖表5:可選的實(shí)現:特別的一對x關(guān)聯(lián)表
不鼓勵的映射 我們已經(jīng)注意到有些開(kāi)發(fā)者選擇有缺陷的映射。我們要注意這些映射以便可以避免。 合并。不要合并多個(gè)類(lèi),不要把關(guān)聯(lián)強制成為一個(gè)單獨的表(圖表6)。這樣減少了表的數量,但會(huì )干擾第三范式。
兩次隱藏一對一關(guān)聯(lián)。不要把一個(gè)一對一關(guān)聯(lián)隱藏兩次,每次隱藏在一個(gè)類(lèi)里(圖表7)。這是多余的,無(wú)助于性能。
相同的屬性。不要用相同的屬性來(lái)實(shí)現多個(gè)關(guān)聯(lián)角色(圖表8)。相同的屬性使編程復雜,降低了擴展性。 泛化 現在我們討論泛化。我們這里只論述單個(gè)繼承。 建議的映射 最簡(jiǎn)單的方法是只映射超類(lèi)和每個(gè)子類(lèi)為一個(gè)表。所有的表共享一個(gè)共同的主鍵。應用必須執行子類(lèi)的劃分,因為RDBMS支持。(關(guān)于后者的詳盡的描述,請參閱第4節。)
特別的表。映射超類(lèi)和每個(gè)子類(lèi)為一個(gè)表(圖表9)。所有的表共享一個(gè)共同的主鍵。鑒別器指出每個(gè)子類(lèi)記錄的適當的超類(lèi)表。
圖表9:建議的實(shí)現:分開(kāi)的超類(lèi)和子類(lèi)表
可選的映射 泛化有幾個(gè)可選的映射。 消除。你可以?xún)?yōu)化除去那些除了主鍵外沒(méi)有別的屬性的類(lèi)(圖表10)。這樣減少了表的數量,但提供更少的正規實(shí)現。
減少超類(lèi)屬性。你可以除去超類(lèi)表并把超類(lèi)屬性復制到每個(gè)子類(lèi)(圖表11)。這樣可以有描述每個(gè)對象為一個(gè)表的優(yōu)勢。無(wú)論如何,它將引起數據庫結構的冗余,你查找一個(gè)對象時(shí)可能需要搜索多個(gè)子類(lèi)表。
增加子類(lèi)屬性。作為第三個(gè)可選項,你可以除去子類(lèi)表并存儲所有的子類(lèi)屬性到超類(lèi)表里(圖表12)。這樣用一個(gè)表描述每個(gè)對象,但干擾了第二范式。
圖表10:可選的實(shí)現:消除不必的子類(lèi)表
圖表11:可選的實(shí)現:減少超類(lèi)屬性
圖表12:可選的實(shí)現:增加子類(lèi)屬性
參考完整性 一旦你已經(jīng)建立了表,你就應該定義參考完整性動(dòng)作來(lái)明確對象模型的意義。(不要使用SQL觸發(fā)器來(lái)實(shí)現參考完整性?。┤绻闶褂没诖嬖诘臉俗R,你將不需要傳播更新的結果。我們建議以下對刪除的參考完整性方針: 泛化。級聯(lián)從泛化實(shí)現中產(chǎn)生的外鍵的刪除。
隱藏的關(guān)聯(lián),最小化多樣性為零。正常地把外鍵設為空,但有時(shí)候你可能要禁止刪除。
隱藏的關(guān)聯(lián),最小化多樣性為空。你可以級聯(lián)一個(gè)刪除的結果或者禁止該刪除。
關(guān)聯(lián)表。正常地我們級聯(lián)關(guān)聯(lián)表里對記錄的刪除??墒?,有時(shí)候我們禁止一個(gè)刪除。
我們已經(jīng)簡(jiǎn)要地論及參考完整性,因為它是個(gè)高級話(huà)題。參考有更多的解釋z和例子。 索引 實(shí)現數據庫結構的最后的一步是加入索引來(lái)調整數據庫性能。正常地,你應該為每個(gè)主鍵和候選鍵定義一個(gè)唯一的索引。(多數RDBMS作為SQL主鍵和候選鍵約束的副作用來(lái)建立唯一的索引。)你也應該為每個(gè)被主鍵或候選鍵所約束的外鍵建立一個(gè)索引。
我們強調索引的重要性。外鍵和主鍵的索引使在對象模型里能快速地遍歷是不容懷疑的。你必須包括這些索引否則你將使用戶(hù)感到灰心。你應該在你的數據庫開(kāi)始設計階段里加入索引,因為它們很容易加入并且也沒(méi)有什么好理由推遲加入。
數據庫管理員(DBA)可能為經(jīng)常請求的查詢(xún)定義了額外的索引。DBA也可能采用產(chǎn)品相關(guān)的調整性能的機制。 范式 范式是關(guān)系型數據庫設計的提高數據一致性的有效方法。我們的書(shū)3討論了范式,但我們關(guān)于這個(gè)問(wèn)題卻言過(guò)甚微。我們將利用這篇文章的機會(huì )來(lái)澄清我們的觀(guān)點(diǎn)。如果你不熟悉范式你可以跳過(guò)這節。我們的說(shuō)明是針對關(guān)系型設計人員,他們正在嘗試用面向對象適應他們原有的技能。
范式是正確設計關(guān)系型數據庫的精確的原則。同樣地,它們與使用了什么開(kāi)發(fā)技術(shù)是無(wú)關(guān)的 - 基于屬性的設計、基于實(shí)體的設計、面向對象設計或其它什么。 過(guò)去使用基于屬性設計的方法,開(kāi)發(fā)人員不得不非常注意范式;范式提供了分組數據的根據。相反地,范式對于基于面向對象(或基于實(shí)體)的開(kāi)發(fā)不是很重要。如果你采用OO方法并且你的模型經(jīng)過(guò)很好的構思,那你就正在把數據組織成為有意義的單位,也在本質(zhì)上滿(mǎn)足了范式的規定。如果你愿意,你仍能夠檢查范式,但這樣的檢查是不必要的。 摘要 圖表13總結了我們已經(jīng)陳述的映射規則。這些映射規則的完整例子,包括一個(gè)UML對象模型,能夠在這篇完整的擴展版本里找到(Adobe Acrobat PDF文件)。
圖表13:推薦的映射規則的摘要
把功能映射到SQL命令 對象模型為數據庫應用提供三種主要的用途。 結構。對象模型指明數據庫結構。我們已經(jīng)在第二節探討了這個(gè)方面。
約束。對象模型也指明了能存儲的數據上的重要的約束。相匹配的實(shí)現必須為迎合這些約束而努力。我們的映射規則的處理方法以及第二節里的參考完整性指出了許多約束。(本文沒(méi)有論及的另外的UML構造,能獲取更多的約束。)
潛在估算。一個(gè)對象模型指明潛在估算;它是關(guān)于引起哪些查詢(xún)和如何公式化的藍圖。第三節將簡(jiǎn)要地闡明第三個(gè)目的。
對象模型不僅僅是被動(dòng)的數據結構,相反它們能夠幫助你思考一個(gè)應用的功能。你可以根據遍歷一個(gè)對象模型說(shuō)出它的許多功能。例如,根據我們對一個(gè)模型檢查用例時(shí)的遍歷,我們進(jìn)行思索。這強調對象模型的估算能力對于RDBMS應用是特別重要的,因為遍歷表達式可以直接映射到SQL代碼。
UML對象約束語(yǔ)言(Object Constraint Language,OCL)有助于表達遍歷。點(diǎn)符號導航從對象到對象和對象到屬性。方括號表示對象集合的過(guò)濾器。我們加入冒號(:)操作符來(lái)表示泛化的遍歷;因為我們正常地用多個(gè)表來(lái)實(shí)現一個(gè)泛化繼承,清楚的遍歷很有用。
圖表14里的遍歷表達式例子是基于我們創(chuàng )建的UML對象模型上的(請參閱本文的擴展版本(Adobe Acrobat PDF文件)),我們把它們映射為SQL代碼。我們用冒號開(kāi)始SQL編程變量。
圖表14:對象模型遍歷和SQL代碼的例子
到RDBMS的OO擴展 數據庫團體對RDBMS的OO擴展有興趣。產(chǎn)品和SQL標準正嘗試加入到OO擴展里。我們將簡(jiǎn)要地陳述一下這個(gè)技術(shù)的方向。 抽象數據類(lèi)型(ADT)。這是個(gè)好主意,擴展RDBMS的能力。開(kāi)發(fā)商為這個(gè)技術(shù)使用了許多名字,例如Oracle cartridge和Informix data blades。ADT的缺點(diǎn)是它們把你緊緊綁在特定的一個(gè)開(kāi)發(fā)商上;ADT的范疇超越了SQL標準。因此,你應該只在A(yíng)DT的好處很明顯的時(shí)候才使用。
在關(guān)于A(yíng)DT如何適合數據庫開(kāi)發(fā)的著(zhù)作里有一些混亂。如果你使用OMT開(kāi)發(fā)過(guò)程,你能夠用屬性實(shí)現簡(jiǎn)單域,用ADT實(shí)現復雜域。你仍應該用表實(shí)現類(lèi)。 SQL3指針。最新的SQL標準的版本,SQL3,加入了作為一種數據類(lèi)型的指針?lè )?。顯然,其意圖是支持導航和面向對象。我們對于SQL3指針最友善的評語(yǔ)是,它們是嫁接的,是可以忽略的。更深入的批評是,指針在理論上是荒謬的,增加了復雜性,又沒(méi)有擴展SQL的表達能力。CJ Date在上次的九月對象/關(guān)系型會(huì )議上雄辯地討論了這一點(diǎn)。
好了,那么我們冷淡地對待抽象數據類(lèi)型和SQL指針的指責。但我們相當喜歡面向對象技術(shù)和關(guān)系型數據庫。有兩個(gè)為RDBMS的擴展可以使它們更容易用于OO技術(shù)。我們將很樂(lè )意看到RDBMS開(kāi)發(fā)商把這些能力加入到他們的產(chǎn)品中。 擴展的參考完整性動(dòng)作來(lái)支持泛化。當前的參考完整性機制是單向的。為了完全支持泛化,我們需要一個(gè)雙向的機制。這樣,一條超類(lèi)記錄就可以依賴(lài)一條子類(lèi)記錄。并且,一條子類(lèi)記錄就可以依賴(lài)一條超類(lèi)記錄。我們通過(guò)例子可以最好地解釋這點(diǎn)。
圖表15摘錄于我們的在3的財務(wù)案例學(xué)習。我們用資產(chǎn)超類(lèi)來(lái)統一某些沒(méi)有顯示在摘錄里的通用的數據和功能。一項資產(chǎn)可以是一只股票或股票特權。一只股票可以有許多它的股票特權。例如,IBM股票可以有許多達到價(jià)格和過(guò)期日期的寫(xiě)下的放或叫特權。
圖表15:參考完整性和泛化的例子
我們推薦的泛化實(shí)現是特別的表 - 映射該超類(lèi)和每個(gè)子類(lèi)為一個(gè)表。然后,我們就可以使用參考完整性使股票特權和股票的記錄依賴(lài)于資產(chǎn)。一個(gè)資產(chǎn)記錄的刪除級聯(lián)到相應的子類(lèi)記錄、股票特權或股票的刪除上。我們也能夠定義一個(gè)參考完整性動(dòng)作,這樣一個(gè)股票的刪除就級聯(lián)到關(guān)聯(lián)的股票特權記錄的刪除。
現在問(wèn)題如下。如果我們刪除的一項資產(chǎn)是一只股票,資產(chǎn)記錄的刪除級聯(lián)到引起股票記錄的刪除。隨后,股票記錄的刪除級聯(lián)引起所有股票特權記錄的刪除。但現在參考完整性使我們失敗了:一個(gè)股票特權記錄的刪除并不引起一項資產(chǎn)記錄的刪除。刪除級聯(lián)只能從超類(lèi)走到子類(lèi)。為了完全的行為,級聯(lián)應該雙向地走下去。
當前有用的參考完整性的工作是做更多的編程(也即做更多的工作和風(fēng)險更多故障)。在我們的用例學(xué)習的實(shí)現里,用戶(hù)隨時(shí)要刪除一項是股票的資產(chǎn),我們不得不書(shū)寫(xiě)額外的代碼來(lái)首先檢查關(guān)聯(lián)股票特權的存在性,然后刪除它們。 支持交叉表的記錄劃分。單獨繼承(泛化的最常見(jiàn)方式)的含義是一個(gè)超類(lèi)的每個(gè)實(shí)例都是用多數只有一個(gè)子類(lèi)來(lái)例示?,F在的RDBMS不能容易地加強這個(gè)約束。例如,沒(méi)有什么防止下面的情形。一只股票可以用ID18加入到資產(chǎn)表,用ID18加入到股票表,并且也可以用ID18加入到股票特權表。再一次地,我們?yōu)榱舜_信行為的完整,不得不作額外的編程,而不是寫(xiě)一個(gè)簡(jiǎn)單的聲明的約束
結論
本文陳述了用關(guān)系型數據庫實(shí)現UML模型的快速的概觀(guān)。我們希望本文向你演示的技術(shù)是足夠適宜的。一個(gè)訓練有素的開(kāi)發(fā)人員能夠用關(guān)系型數據庫準備一套優(yōu)秀的OO模型的實(shí)現。如果你要關(guān)于實(shí)現機制的更多的細節,參考3有另外的信息,并且也覆蓋了我們沒(méi)有在這里討論的一些高級模型建模結構。
版權所有:UML軟件工程組織