黃錫剛
摘要:文章討論的是在傳統(tǒng)中間件環(huán)境下,在數(shù)據庫多層訪問模型的基礎上,利用對象/關系映射如何實現(xiàn)對象持久性設計。
關鍵詞:持久性對象;關系數(shù)據庫;三層模型;對象標識
中圖分類號:TP312文獻標識碼:A文章編號:1006-8937(2009)10-0025-02
持久對象需解決內存中瞬時對象與其他存儲設備上持久對象的數(shù)據格式轉換問題。主要的存儲設備有以下的三種:
①文件系統(tǒng)??梢酝ㄟ^串行化對象來將對象保存在一個文件中。當應用程序設計中要求使用文件系統(tǒng)作為持久性基礎設施來實現(xiàn)應用程序中相關對象的持久性時,我們可以自定義一個文文章件的格式,將對象的狀態(tài)存儲在該文件中。
②對象數(shù)據庫。這是保證對象持久性的最合理的做法。但大多數(shù)公司還只是剛開始研究對象數(shù)據庫,所以還不是主流的存儲介質。
③關系數(shù)據庫。目前大多數(shù)先進的應用程序都使用面向對象的數(shù)據結構。但在企業(yè)級的應用中大部分的數(shù)據庫系統(tǒng)仍然是關系型數(shù)據庫。雖然面向對象的數(shù)據結構對很多應用必不可少,但我們仍然要考慮很多原有系統(tǒng)的需要,所以關系數(shù)據庫的應用還是主流。
持久性一般可以分成兩類:空間上的持久性和時間上的持久性??臻g上的持久性是在網絡中傳遞對象的狀態(tài),例如:遠程方法調用RMI(Remote Method Invocation, RMI是java分布式對象(EJB)的通信基礎設施)將對象狀態(tài)串行化后,通過socket傳輸串行化結果。時間上的持久性中,輕量型持久對象通常保存在本地文件系統(tǒng)中;重量型持久性對象通常采用:O/R映射(關系/對象映射)+RDB(關系數(shù)據庫)來解決。
最簡單的持久性實現(xiàn)方案是在應用程序啟動時從文件裝入相關對象的狀態(tài),在程序結束時將相關對象的狀態(tài)存到該文件中。但當我們要采用可擴展性更好的持久性方案時,譬如實現(xiàn)對象瞬時(transient)狀態(tài)的更新與其持久性是同步的的時候,O/R+RDB的解決辦法就顯得非常實用了。
1關系數(shù)據庫的應用
企業(yè)級的應用大多數(shù)都采用三層模型來使用中間件訪問數(shù)據。典型的三層模型由上到下分別是:表示層、業(yè)務邏輯層、數(shù)據層。三層結構將業(yè)務邏輯抽取出來作為一個獨立的中間層。業(yè)務邏輯層是對企業(yè)所有業(yè)務邏輯的一種抽象,對上:為表示層提供了更高級的API;對下:封裝了整個數(shù)據層。企業(yè)級的應用還可以是以三層結構為基礎的擴展,例如:在業(yè)務邏輯層與數(shù)據層之間引入一層“持久對象層”,持久對象層可以實現(xiàn)對象/關系映射,數(shù)據類型轉換等功能。
數(shù)據庫是企業(yè)級應用的基礎設施。在開發(fā)數(shù)據庫應用系統(tǒng)時,引入對象—關系映射中間件是提高開發(fā)效率、提升軟件可維護、擴展性的需要。成熟的對象—關系映射中間件產品,可以把內存中的對象持久化到數(shù)據庫中,但前提是我們必須設計好自己的持久性對象、合理的對象持久性方案。持久性保存數(shù)據到一個數(shù)據庫需要注意的是盡量的保持對象持久性的高度透明化。理由有以下4點:①企業(yè)應用需要實現(xiàn)持久性對象。②代表業(yè)務邏輯的對象可獨立于使用它們的程序而存在。③多個應用程序可能需要工作在同一個對象上。④當對象與另一個對象交流時,不必了解該對象在內存還是在外存。
2O/R映射基本規(guī)則
對象范式與關系范式之間存在阻抗不匹配問題,利用已有的O/R映射模式可幫助設計人員避免實現(xiàn)對象持久性的陷入誤區(qū)。基本的映射規(guī)則有以下的三點:
①將屬性影射為列。并不是所有屬性都是持久性的。通常,依賴屬性都不是持久性的。例如:記帳憑證中的借、貸合計。
②將類映射為表。形式可以是多個類映射到單張表、單張表映射到多張表。多個類映射到同一張表這種情況是由于對象范式含有數(shù)據與操作,關系范式僅有數(shù)據,所有O/R映射丟失操作后,某些數(shù)據可能更適合合并。一個類映射到多張表,這種情況一般是由于要考慮程序效率才這樣做。在某些情況下劃分多張表會提高性能,但如果執(zhí)行涉及連接的操作則通常反而降低性能。
③類間關系(繼承、聚集、關聯(lián))的映射。繼承關系的映射,一般有三種形式:一是整個類層次使用一張表,類層次中所有類的所有屬性均存放在該表中。二是每個葉結點類使用一張表。三是每個類使用一張表,該表只保存OID(對象標識)以及對應類自己的屬性(不含所繼承的屬性)。關聯(lián)與聚類關系的映射從關系范式的角度來看,區(qū)別僅在于耦合程度不同而已。聚類耦合程度高:通常對“整體”操作都伴隨著對“部分”。關聯(lián)則不存在這么
高的相關度。
3對象持久性的設計方案
為了將設計階段的工作過程清晰的表達出來,文章簡單的設計一個餐館訂餐小系統(tǒng)來說明整個設計過程。
第一步:標志那些數(shù)據需要持久性。
對象標識(OID)唯一標識關聯(lián)對象/關系,在關系范式里該標識稱為關鍵碼(key),在對象范式里就是作為持久對象標識。OID的實現(xiàn)既可以是一個輕量級對象,也可以是整數(shù)、字符串等,OID設計的基本要求是唯一性和不變性。OID有3種層次的唯一性:①在同一個類中具有唯一性;②在同一個類層次中具有唯一性;③在所有對象中均有唯一性。唯一性范圍越大,則通常的開銷也越大。
在UML中類是作為指派持久性的基本單位。因為并不是每一個類都需要持久性,所以在設計過程中用帶標簽的值來標志持久性,可以采用(名字、值)簡寫的方式來表示,名字為類名,值分別記為Persistent(持久的)和transitory(暫時的),其中默認情況下是transitory(如圖1所示)。這一步的設計我們要注意的是兩個持久類之間的關聯(lián)也是持久的。
第二步:設計合適的數(shù)據庫模式。
在數(shù)據庫設計階段,簡單的設計4張表:Table(桌子) 、Customer(顧客)、Walkin(無預訂散客)、Reservation(預約)。每一張表添加顯式的對象標識(OID),實現(xiàn)鏈接時用這些對象標識作為外碼(FK)。由于文章所設計的Booking類是一個抽象類,可以簡單地將其具體之類映射為表。
第三步:解決對象與關系的同步問題。
這時要解決的問題是:哪一個對象的職責應包含往數(shù)據庫存放或從數(shù)據庫裝入對象的功能?因為指派為已有的類會導致聚合性降低,所以引入一個新的類專門執(zhí)行該職責。為每一持久類定義一個映射類(Mapper)。在設計模型中引入對象標識,從而在領域模型之外亦可實現(xiàn)持久性。為每一持久性類定義子類,在子類中添加對象標識。Mapper類處理具有持久性的子類。
第四步:持久性體系結構設計。
Persistent子類和Mapper類依賴于它們所支持的類。它們應出現(xiàn)在業(yè)務邏輯層,但Restaurant類依賴于 Mapper類。將業(yè)務邏輯層劃分為兩個子包。從而盡量避免了子程序包Persistency的變化對子程序包Domain帶來的影響。
4結 語
實現(xiàn)重量型持久性對象文章推薦的解決方案是O/R+RDB。持久性對象的設計的過程為:①標識哪些數(shù)據需要持久性;②設計一個合適的數(shù)據庫模式;③解決對象與關系的同步問題。最后總結自己的持久性體系結構。文章所描述的持久性對象的設計過程可以為解決同類問題的提供參考。
參考文獻:
[1] 宋波,劉杰,杜慶東.UML面向對象技術與實踐[M].北京:科學出版社,2005.
[2] (美)理查德森著.沈文炎譯.Java高級編程:JDK5[M].北京:機械工業(yè)出版社,2006.
[3] (美)霍頓著.潘曉雷譯.Java2入門經典:JDK5[M].北京:機械工業(yè)出版社,2006.