1?引言?
??? 目前的數(shù)據(jù)庫管理系統(tǒng)" title="管理系統(tǒng)">管理系統(tǒng)(DBMS)中基本上是關(guān)系型數(shù)據(jù)庫(RDBMS)占據(jù)著主導(dǎo)地位。從形式上來說,關(guān)系數(shù)據(jù)庫" title="關(guān)系數(shù)據(jù)庫">關(guān)系數(shù)據(jù)庫是一系列行列規(guī)整的表的集合,但邏輯上數(shù)據(jù)庫中數(shù)據(jù)是對現(xiàn)實世界中事物的抽象描述。而面向?qū)ο?/a>" title="面向?qū)ο?>面向?qū)ο?/a>建模的過程也是對事物的抽象過程。所以關(guān)系數(shù)據(jù)庫中的數(shù)據(jù)和對象二者間存在一種以其共同描述的現(xiàn)實世界中的事物為紐帶的聯(lián)系。利用面向?qū)ο笏枷雽﹃P(guān)系數(shù)據(jù)庫中的數(shù)據(jù)訪問" title="數(shù)據(jù)訪問">數(shù)據(jù)訪問進行抽象和封裝,可以有效地提高系統(tǒng)性能、降低開發(fā)成本。本文對傳統(tǒng)的數(shù)據(jù)庫訪問技術(shù)的用Java類進行了面向?qū)ο蟮某橄蠛头庋b,并就其中目前廣泛存在的問題" title="存在的問題">存在的問題提出了一種通用的解決方案,極大地提高了開發(fā)效率。
2?基本的面向?qū)ο蟮姆庋b方法?
??? 面向?qū)ο笏枷胧悄壳白顬榱餍械脑O(shè)計思想。充分利用面向?qū)ο蟮乃枷?,對?shù)據(jù)庫數(shù)據(jù)訪問進行抽象和封裝,將帶來以下幾個好處:①對數(shù)據(jù)和過程進行抽象封裝,提高了系統(tǒng)的模塊獨立性,降低了系統(tǒng)的耦合度;②對相關(guān)實體的封裝,有利于構(gòu)件復(fù)用;③信息隱蔽,減少發(fā)生錯誤時副作用的傳播;④繼承性使得對超類的修改可以立即作用到所有子類。?
2.1 實體類?
??? 關(guān)系數(shù)據(jù)庫數(shù)據(jù)訪問操作,可以利用面向?qū)ο蟮乃枷脒M行封裝,可以建立“表(或視圖等)—對象”的對應(yīng)關(guān)系,把數(shù)據(jù)的取、增、刪、改操作封裝成類方法。
??? 在數(shù)據(jù)庫中,大量的數(shù)據(jù)訪問許多是對表最基本的數(shù)據(jù)庫操作(對記錄的取、增、刪、改操作)或這些操作的組合。關(guān)系數(shù)據(jù)庫中的表可以映射為類,表的字段可以映射成類的屬性,對表的操作可以映射成類的方法,表的記錄(行)可以映射成類的對象?,F(xiàn)在以一個簡化的學(xué)校信息管理系統(tǒng)為例說明數(shù)據(jù)的訪問過程。圖1中每個方框表示一個實體,在數(shù)據(jù)庫中每個實體用一個表表示(見圖2)。

??? 如上述的學(xué)校管理系統(tǒng)中就可以建立學(xué)校類、學(xué)生類、教師類、課程類等。一個實體類的屬性通常以對應(yīng)的表的字段命名;其方法通常是以對某個字段信息的操作命名。比如學(xué)生類有學(xué)生編號、姓名、性別等屬性,有取編號、設(shè)置編號等以getXX和setXX的方法(XX對應(yīng)于某一屬性)。
2.2實體管理類?
??? 在對“實體”(比如學(xué)生Student)抽象和包裝的過程中,往往需要一個對應(yīng)的“實體管理類”負責(zé)對實體的管理工作。因為“實體對象”本身側(cè)重于對單個實體的描述,而數(shù)據(jù)庫訪問通常是對一組滿足特定條件的記錄(對應(yīng)于一組實體對象)進行操作,所以需要在“YY實體” 層(YY表示某類實體名)之上有一具有對應(yīng)管理功能的類層次,稱之為“YY實體管理類”。比如“學(xué)生類”(Student)的管理類為“學(xué)生管理類”(StudentManage)。實體管理類主要的方法對應(yīng)于相應(yīng)實體的查找、增加、刪除、修改、列表等操作。一個實體管理類的方法通常是一組有g(shù)etYY、addYY、deleteYY、editYY、listYY特征的成員函數(shù)。
??? 假設(shè)現(xiàn)需查詢在特定成績段的學(xué)生,就可以調(diào)用學(xué)生管理類的以成績段為參數(shù)的類方法得到所有滿足查詢條件的學(xué)生,如果想得到這些學(xué)生的信息,則可以調(diào)用學(xué)生對象的“getXX”方法實現(xiàn)。下面以學(xué)校管理系統(tǒng)的學(xué)生實體為例進行抽象和封裝。
public abstract class Student{//學(xué)生類?
? String id = null;//學(xué)生編號?
? String name = null;//學(xué)生姓名?
? …?
? public abstract void setId(String _id);//設(shè)置學(xué)生實體編號?
? public abstract String getId();//取學(xué)生實體編號?
? ...?
}?
下面這個類是相應(yīng)的一個學(xué)生管理類的代碼: ?
public class StudentManage{//學(xué)生管理類?
? public Student findStudentById(String _id) {…}//查找某一編號的學(xué)生?
public boolean deleteStudentById(String _id) {…}//刪除某一編號的學(xué)生?
? ...?
}?
2.3 存在問題?
??? 可以看出,通過以上的對學(xué)生信息相關(guān)操作的封裝,對學(xué)生信息的程序處理邏輯上更加清晰,同時也提高了軟件的復(fù)用程度,降低了系統(tǒng)的偶合度。但是該模式也有明顯的弊端:①由于實際系統(tǒng)中大量表的存在,要編寫大量相應(yīng)的封裝類(實體類和相應(yīng)實體的管理類),封裝類的個數(shù)隨著表的數(shù)量(N)成約為N*2的比率增長; ②封裝類的大?。ㄖ饕浅蓡T變量和成員函數(shù)的個數(shù))隨著表的字段個數(shù)(M)的增加成約為M*λ(λ為封裝類的平均成員函數(shù)個數(shù))的比率增長;③對數(shù)據(jù)庫中表結(jié)構(gòu)的變動會傳播到類的定義上來。?
3?通用解決方案?
3.1解決思路?
??? 上面所提出的抽象和封裝方案問題在于實體的特征和功能(對應(yīng)于類的屬性和方法)是靜態(tài)的:實體的特征和功能在類的定義時就確定下來了(以字段命名),在程序的運行過程中也無法動態(tài)改變或更新。這樣就必須把幾乎所有的字段及其操作都對應(yīng)成類的屬性和方法。通用解決方案就是試圖找到一條能夠克服以上弊端的途徑。其核心思想是將數(shù)據(jù)庫表及其字段信息存儲在數(shù)據(jù)庫中,動態(tài)地創(chuàng)建實體。該實體類的定義不與特定的表關(guān)聯(lián),但能與某個表動態(tài)關(guān)聯(lián)并執(zhí)行特定的功能。
??? 該方案的實現(xiàn)有兩個問題必須解決:
①動態(tài)創(chuàng)建邏輯實體。動態(tài)創(chuàng)建邏輯實體需要在給定實體名的條件下能獲得該實體在特定條件下所擁有的特征。實體特征實際上是一個<表名,字段名>的二元組。目前的解決方法是在庫中預(yù)先創(chuàng)建一個實體特征表,有三個基本字段:表名、字段名、字段類型。
②動態(tài)賦予邏輯實體的特征和功能。目前的解決方法是把實體的特征和特征類型用哈希表(Hashtable)的形式存儲在類中。實體特征的增、刪可以通過對哈希表的操作(put和remove)實現(xiàn)。一個實體屬性一般有兩個實體方法與之對應(yīng),即取、設(shè)置該屬性值的操作。如果把屬性名稱作為實體方法的參數(shù)以標(biāo)識對某個屬性值的操作,這樣就可以避免為每個屬性值都要編寫對應(yīng)的方法(getXX和setXX)。
??? 下面就以在學(xué)校信息系統(tǒng)中的應(yīng)用進行說明。在庫中建立一實體特征表UNIT_ATTR,有三個字段:實體名(TABLE_NAME),實體屬性(ATTRIBUTE_NAME),屬性類型(ATTRIBUTE_TYPE)。定義兩個類GerneralUnit和GerneralUnitManage。
3.2通用實體類?
??? 下面是對通用實體類的定義:?
public abstract class GerneralUnit {//通用實體類?
? protected Hashtable attributes = null;//實體的特征(屬性-屬性值)存儲在哈希表中?
? protected String unitName = null;//實體(表)名?
? protected Hashtable field_type =null;//(屬性—屬性類型)?
? public abstract String getStringAttribute(String fieldName);//取某個String類型的屬性值,屬性名作為方法的參數(shù)?
? public abstract void setStringAttribute(String fieldName,String value);//設(shè)置某個String類型的屬性值,屬性名作為方法的參數(shù)?
? ...?
}?
??? 通過這種方式,可以將實體的方法與數(shù)據(jù)庫的表的字段名動態(tài)地關(guān)聯(lián)起來,其中一個好處就是避免了2節(jié)中的問題②③,實體的方法不會隨著關(guān)系表的增長而增長,其變動對實體類的定義沒有影響。更重要的一個好處是這種動態(tài)關(guān)聯(lián)使得該實體類成為通用的實體類,這個通用實體類可以隨關(guān)系表的不同,可能代表“學(xué)生類”、“教師類”、“課程類”、“工資類”等等,解決了問題①。?
3.3通用實體管理類?
??? 下面是對通用實體管理類的定義:?
public class GerneralUnitManage {//通用實體管理類?
? //通過實體主特征查找實體,并返回動態(tài)創(chuàng)建的實體對象?
? public GerneralUnit[] getUnits(String unitName,Hashtable mainAttribute){…}?
? public deleteUnit(String _UnitName,Hashtable mainAttribute){…}?
...?
}?
??? 在實體管理類的方法中,對數(shù)據(jù)庫的操作基本上分為兩種情況:一種是從數(shù)據(jù)庫關(guān)系表中取數(shù)據(jù),并根據(jù)這些數(shù)據(jù)為實體屬性賦值;另一種是根據(jù)實體的屬性值對關(guān)系表的記錄進行添加、修改或刪除。通用性是通過獲取數(shù)據(jù)庫中表及其字段的相應(yīng)信息,并根據(jù)這些信息動態(tài)賦予實體相應(yīng)屬性值(或根據(jù)動態(tài)賦予實體的屬性值來進行相應(yīng)的數(shù)據(jù)庫操作)來實現(xiàn)的。下面以GerneralUnitManage類中的查找實體方法getUnit為例進行說明:?
public GerneralUnit[] getUnits(String unitName,Hashtable mainAttribute) {//參數(shù):實體名、關(guān)鍵特征?
…?
? String strSQL = "select ZDMC, SJLX, ZDHY from VVVV where BMCV='" + unitName + "'";//查找關(guān)系表的所有字段?
? while(rs.next()) {?
??? String key = rs.getString("ZDMC");//將實體與關(guān)系表關(guān)聯(lián)起來?
??? …?
??? info.setAttributeType(key,dataType);?
??? …?
}?
String findSQL =…//根據(jù)查找實體屬性生成SQL語句?
ResultSet rs = stmt.executeQuery(findSQL);//執(zhí)行生成的SQL語句,根據(jù)結(jié)果集生成相應(yīng)實體?
while(rs.next()){?
? ??…?
??? for (i = 0; i < count; i ++ ) {//為實體賦予屬性值?
????????????? key = keysInDb.get(i).toString();?
????????????? unit.setAttribute(key, rs.getObject(key));?
??????????????????????? ? units.add(unit);?
??? }?
}?
… ?
if(bSuccessToGet)return units;?
else return null;?
}?
??? 因為能將實體和關(guān)系表動態(tài)關(guān)聯(lián),該實體管理類具有通用性。通過對其方法中的參數(shù)設(shè)置將不同的關(guān)系表與通用實體類關(guān)聯(lián)起來,從而避免了2節(jié)中提到的類的數(shù)量隨數(shù)據(jù)庫中關(guān)系表的數(shù)量正比增長的問題。?
該方案是針對一般情況而設(shè)計的。對于某些特殊應(yīng)用,可以將上述通用方案的某些方法進行重載以滿足部分特殊需求。?
4?結(jié)束語?
??? 本文針對面向?qū)ο蟮年P(guān)系數(shù)據(jù)庫數(shù)據(jù)訪問實現(xiàn)中存在的問題,提出了一種新的通用方案。應(yīng)用該方案可以一次性編寫兩個通用的類代替原來的諸多實體類和實體管理類,代碼量大大減少。并且這兩個類可以幾乎無需修改地應(yīng)用到其他系統(tǒng)中。該方案已經(jīng)在多個軍隊自動化系統(tǒng)的開發(fā)中得到實際應(yīng)用。雖然本文是以三層結(jié)構(gòu)模型下的信息系統(tǒng)開發(fā)為例進行說明的,但是該方案對兩層結(jié)構(gòu)模型下的開發(fā)也有一定的借鑒意義。
參考文獻?
1、? 唐潛、楊德華,用JAVA類封裝RDB庫表──在關(guān)系數(shù)據(jù)庫上運用OO技術(shù)探討,計算機應(yīng)用研究,1999.11
2、? Scott W. Ambler,Mapping objects to relational databases,http://www-900.ibm.com/developerWorks/cn/components/mapping-to-rdb/index_eng.shtml,2000.7
3、? 王建華等譯,最新Java2核心技術(shù)(卷Ⅱ:高級性能),機械工業(yè)出版社,2003.1
