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