Java發(fā)明以來(lái),在短短的幾年之間,迅速占領(lǐng)了從桌面應用(J2SE)到服務(wù)器(J2EE),再到小型設備嵌入式系統(J2ME)的應用開(kāi)發(fā)市場(chǎng),其語(yǔ)言吸取了SmallTalk的一切皆對象的理念,擺脫了C++的歷史累贅,簡(jiǎn)潔、自由的風(fēng)格贏(yíng)得了很多開(kāi)發(fā)者的喜愛(ài)。從JDK1.1開(kāi)始,Java成為實(shí)用的語(yǔ)言,而不是被人觀(guān)望的新品秀;再經(jīng)過(guò)JDK1.2的大量增強(尤其是Collection Framework),JDK1.3的虛擬機效率提升(HotSpot),JDK1.4的融合百家之長(cháng)(Logging、RegExp、NewIO等),現在已經(jīng)是成熟穩重,頗顯大家風(fēng)范。
在企業(yè)級市場(chǎng)上,大部分的應用建立在數據庫基礎上,數據是企業(yè)的生命,傳統開(kāi)發(fā)語(yǔ)言,包括面向過(guò)程的C、面向對象的C++、變種Pascal的Delphi(非常棒的語(yǔ)言,我用過(guò)四年),面向數據的PowerBuilder等等,先后在數據庫開(kāi)發(fā)的舞臺上展現風(fēng)姿。Java當然不會(huì )放過(guò)這些,于是,出現了JDBC。在JDBC的幫助下,Java也迅速滲入數據庫開(kāi)發(fā)的市場(chǎng),尤其是面向企業(yè)服務(wù)器的應用開(kāi)發(fā)。
今天要談的JDO,與JDBC有非常密切的關(guān)系,盡管JDO并不是只面向JDBC的數據對象包裝規范。下面先簡(jiǎn)單地介紹一下JDBC。
關(guān)系數據庫的歷史一言難盡,我只能從我的接觸經(jīng)歷和所見(jiàn)所聞,簡(jiǎn)單地敘述一下。最早的時(shí)候,計算機還只在一些大型的研究機關(guān)露面,并不是普羅大眾可以涉及的。蘋(píng)果電腦將個(gè)人電腦引入民間,再隨著(zhù)IBM的PC標準開(kāi)放,個(gè)人電腦逐步普及開(kāi)來(lái),加上微軟的DOS操作系統,以及Borland的Turbo系列語(yǔ)言開(kāi)發(fā)環(huán)境,老百姓發(fā)現原來(lái)電腦可以做這么多事!后來(lái),出現了DBASE,一個(gè)簡(jiǎn)單的關(guān)系數據庫系統,和SQL語(yǔ)言。后來(lái),Borland看到了數據庫的市場(chǎng)前景,推出了Paradox(也是當今Delphi和C++Builder中仍然使用的Paradox),一舉占領(lǐng)了民用數據庫的大部分江山,之后,Borland干脆收購了Dbase,后來(lái)又購買(mǎi)了InterBase,將數據庫市場(chǎng)的領(lǐng)先優(yōu)勢一直保持到Windows3.0出現。這時(shí)候,微軟在Windows1.0和2.0被人痛罵之后頑強地推出3.0,以及更穩定的3.1和Win32API,造就了個(gè)人電腦桌面操作系統的霸主地位,在Borland未警覺(jué)的情況下,購買(mǎi)了同樣具有類(lèi)Dbase數據庫技術(shù)的Fox公司,并迅速將其易用化,形成了FoxBase,后來(lái)演變成FoxPro,逐漸超過(guò)了Borland,成為個(gè)人電腦數據庫的大戶(hù)。微軟再接再勵,為簡(jiǎn)單易用而低負荷要求的數據庫應用開(kāi)發(fā)了Access,贏(yíng)得了廣大開(kāi)發(fā)人員的心。當然,同期的Oracle、Sybase、Informix等商用數據庫憑專(zhuān)注于企業(yè)級數據庫技術(shù)成為高端的幾位領(lǐng)軍人物。微軟當然也想成為高端數據庫供應商之一,于是自行開(kāi)發(fā)一套面向企業(yè)級應用的數據庫,不過(guò)很快項目夭折,微軟不甘心,購買(mǎi)了Sybase的底層TDS技術(shù),包裝成了SQL Server,憑微軟的高度易用性的特點(diǎn),也占領(lǐng)了不少市場(chǎng)。
當市場(chǎng)上出現眾多的數據庫產(chǎn)品之后,Borland和微軟都發(fā)現自己擁有的數據庫產(chǎn)品挺多,市場(chǎng)也不小,不同的產(chǎn)品給用戶(hù)帶來(lái)不同的配置任務(wù),不利于所有產(chǎn)品的推廣,于是,兩者紛紛開(kāi)始制定數據庫訪(fǎng)問(wèn)的規范,微軟推出了ODBC,其面向開(kāi)發(fā)人員的親和性,逐步獲得了認可,同時(shí),Borland糾集了IBM和Novell也推出了IDAPI數據庫接口規范,也就是今天BDE的核心,不過(guò)后來(lái)Novell和IBM先后退出,只剩Borland獨力支撐。不過(guò)Borland是一個(gè)技術(shù)實(shí)力雄厚的公司,其技術(shù)一向領(lǐng)先于微軟,BDE的性能比初期的ODBC不知道要好多少倍,后來(lái)微軟偷師學(xué)藝,把連接池等技術(shù)加到ODBC中,在Delphi3.0及其BDE在市場(chǎng)上風(fēng)光無(wú)限的時(shí)候,逐步趕了上來(lái)并有超過(guò)。直到今天,BDE仍是Borland的產(chǎn)品線(xiàn)上的數據庫訪(fǎng)問(wèn)標準,而微軟如果不是將ODBC和多數數據庫的客戶(hù)端內嵌進(jìn)Windows的話(huà),估計BDE仍是市場(chǎng)的贏(yíng)家。不過(guò),微軟是玩弄市場(chǎng)的老手,通過(guò)對操作系統的壟斷,其數據庫產(chǎn)品和ODBC標準終究占據了多數開(kāi)發(fā)市場(chǎng)。
Java開(kāi)始涉及數據庫應用后,Sun就極力制定Java的數據庫規范,JDBC API就是類(lèi)似ODBC一樣,對數據庫訪(fǎng)問(wèn)的底層協(xié)議進(jìn)行最基本的包裝,然后形成一套統一的數據訪(fǎng)問(wèn)接口,數據庫連接、SQL語(yǔ)句句柄、結果集,都帶有ODBC的影子。以方便配置為目的,Sun極力推薦完全瘦客戶(hù)端的TYPE 4型JDBC驅動(dòng),這是一個(gè)不需要安裝數據庫客戶(hù)端的驅動(dòng)規范,是現在使用最多的。當然,為了保持與舊的數據庫兼容,JDBC規范中包括了專(zhuān)用于連接ODBC的TYPE 1驅動(dòng)和需要安裝數據庫客戶(hù)端的TYPE 2驅動(dòng),以及可以由廠(chǎng)商在數據庫服務(wù)端專(zhuān)門(mén)提供面向JDBC的服務(wù)的TYPE 3驅動(dòng)。
JDBC最早出現時(shí),還不屬于標準JDK的一部分,而是作為一個(gè)額外包提供下載。后來(lái),隨著(zhù)Java編寫(xiě)的數據庫應用的的增多,和JDBC規范本身的逐漸成熟,JDBC終于成為JDK1.1的一部分。
JDBC目前最新的是3.0版本,還有正在討論中的4.0版本。實(shí)際上,在開(kāi)發(fā)中使用得最多的還是1.0中的API,2.0中主要增加了可雙向滾動(dòng)的結果集、更新批處理等提高可用性和性能的API,3.0主要增加了連接池、可更新的結果集等特性。4.0將在可管理性、連接池規范化等方面再做改進(jìn)。
現在的程序員,沒(méi)有不知道面向對象的。作為接近真實(shí)客觀(guān)世界的開(kāi)發(fā)概念,面向對象使程序代碼更易讀、設計更合理。在普遍存在的數據庫應用領(lǐng)域,開(kāi)發(fā)人員對面向對象的追求從未停止過(guò)。從八十年代開(kāi)始,就有很多公司和研究機構在進(jìn)行著(zhù)面向對象與數據庫結合的研究。
面向對象的語(yǔ)言最早有好幾種雛形,IBM的SmallTalk是其中最為流行的,在SmallTalk中,一切都是對象,一切都是類(lèi),它將面向對象的概念發(fā)揮到了極致。面向對象的編程比起傳統的面向過(guò)程的方式挺進(jìn)了一大步,使人們認識到:原來(lái)軟件可以這樣寫(xiě)。不過(guò),由于計算機基本結構與底層硬件體系和系統軟件的限制,SmallTalk還不能在理想的性能前提下推廣到普通的應用上,這一點(diǎn)暫時(shí)限制了SmallTalk的發(fā)展,接著(zhù),C語(yǔ)言的面向對象版C++出現了,由于使用C語(yǔ)言的人很多,C++很快成為面向對象編程的主流語(yǔ)言。不過(guò),為了保證與C的兼容,C++保留了很多面向過(guò)程的痕跡,比如惡心的指針、全局變量等等。Pascal的改進(jìn)版Object Pascal相對來(lái)說(shuō)安全許多,后來(lái)Borland干脆將Object Pascal換了個(gè)名字,叫Delphi,從此開(kāi)創(chuàng )了一片面向對象編程的新世界, Delphi的嚴謹語(yǔ)法和快速編譯吸引了眾多的應用開(kāi)發(fā)者,加上Borland的完美的VCL組件體系,比起MFC來(lái)方便而容易,另外,Delphi完整的數據庫組件,也將數據庫開(kāi)發(fā)變得簡(jiǎn)單而容易,Delphi再次成為成熟的面向對象開(kāi)發(fā)語(yǔ)言。微軟當然不會(huì )放過(guò)這些,通過(guò)將MFC內置到操作系統中,微軟的VC++也搶回一些市場(chǎng)。這也是為什么Delphi開(kāi)發(fā)的應用程序編譯后會(huì )比VC、VB開(kāi)發(fā)的程序大的原因。
1995年,Sun的一個(gè)開(kāi)發(fā)小組本來(lái)為了小型嵌入式系統開(kāi)發(fā)OAK語(yǔ)言,結果無(wú)心插柳柳成蔭,發(fā)展出了Java語(yǔ)言,它是一個(gè)完全擺脫了傳統語(yǔ)言的各種負擔的面向對象的語(yǔ)言,當然,也保留了一些非面向對象的核心(原始類(lèi)型)以保證速度?,F在Java也為最流行的面向對象語(yǔ)言之一。當然,微軟同樣不會(huì )放過(guò)它,擅于模仿的微軟立即弄出一個(gè)C#來(lái)與之競爭,并在C#中保留了一些變種的指針(指代)以吸引傳統的C開(kāi)發(fā)者。關(guān)于這些語(yǔ)言的各自特點(diǎn),這里就不一一贅述了。
數據庫是企業(yè)級應用不可缺少的,因此,在面向對象流行的時(shí)候,數據庫廠(chǎng)商也在進(jìn)行著(zhù)數據對象化的研究。這些研究在上個(gè)世紀八十年代就初現端倪。
數據庫的對象化一般有兩個(gè)方向:一個(gè)是在主流的關(guān)系數據庫的基礎上加入對象化特征,使之提供面向對象的服務(wù),但訪(fǎng)問(wèn)語(yǔ)言還是基于SQL;另一個(gè)方向就是徹底拋棄關(guān)系數據庫,用全新的面向對象的概念來(lái)設計數據庫,這就是對象數據庫ODBMS。
隨著(zhù)許多關(guān)系數據庫廠(chǎng)商開(kāi)始提供對象化服務(wù),各自的接口開(kāi)始互不兼容,在經(jīng)歷一些麻煩之后,關(guān)系數據庫廠(chǎng)商感覺(jué)到規范化的必要,因為當初關(guān)系數據庫雄霸天下時(shí)SQL92標準起了很大作用,大家可以按照統一的編程方式來(lái)訪(fǎng)問(wèn)高性能的商用數據庫。
關(guān)系數據庫廠(chǎng)商集中起來(lái),重新將對象化服務(wù)規范起來(lái),形成了SQL99規范,將其中的對象結構等內容規范起來(lái),開(kāi)始一個(gè)嶄新的面向對象的關(guān)系數據庫(ORDBMS)的歷程。
JDBC3.0就是在這種情況下出臺的,它將對關(guān)系數據庫中的對象服務(wù)的訪(fǎng)問(wèn)API規范起來(lái),為Java平臺提供了訪(fǎng)問(wèn)ORDBMS的標準方式。當然,JDBC3.0對傳統的SQL操作也進(jìn)行了很多功能增強。
Oracle是一個(gè)傳統的關(guān)系數據庫廠(chǎng)商,在對象化的道路上,Oracle當然采取追加對象化特征的道路,以侵入數據對象化的市場(chǎng),保持Oracle在數據庫領(lǐng)域的領(lǐng)導地位。如果說(shuō)Oracle7.4使Oracle走向全盛的話(huà),從Oracle8開(kāi)始,Oracle就成為關(guān)系數據庫加對象類(lèi)型的先驅。在Oracle8中,我們可以定義一些數據結構(Record),將普通的類(lèi)型包裝在其中成為數據元素,然后可以在客戶(hù)端按Record結構進(jìn)行訪(fǎng)問(wèn),初步提供了面向對象的數據庫服務(wù)。
對象數據庫就是采用全新的面向對象概念來(lái)設計數據庫的全新數據庫類(lèi)型。在這方面,主要以一些大學(xué)研究機構進(jìn)行設計和開(kāi)發(fā),有些也形成了產(chǎn)品,不過(guò)由于市場(chǎng)方面的原因(主要是關(guān)系數據庫的容易上手和市場(chǎng)絕對領(lǐng)導地位)和ODBMS先天的一些弱點(diǎn)(比如查詢(xún)引擎很難優(yōu)化),使ODBMS沒(méi)有象關(guān)系數據庫那樣流行起來(lái)。
不過(guò)對象數據庫的對象化特點(diǎn)還是令人割舍不下,目前還是有一些很好的產(chǎn)品在市場(chǎng)上,從商用的到免費的都用。目前在ODBMS領(lǐng)域占據領(lǐng)導地位的是Versant、FastObjects和ObjectStore等幾大廠(chǎng)商,并且,市場(chǎng)份額也在逐步擴展。免費的產(chǎn)品包括C++編寫(xiě)的Ozone、純Java的db4o等等。還有一些研究機構開(kāi)發(fā)一些底層的面向對象數據庫引擎,但只提供一些底層的API,不提供管理方面的功能,以及一些算法提供開(kāi)放式接口,讓廠(chǎng)商去選擇和實(shí)現。比如美國威斯康新大學(xué)計算機系數據庫組的SHORE引擎,就是一個(gè)非常出色的面向對象數據庫引擎,現在還在積極的更新中,一些其它研究機構和數據庫廠(chǎng)商采用它完成了自己的特別的對象數據庫,比如專(zhuān)用于地理信息的數據庫、專(zhuān)用于宇宙空間數據研究的數據庫等等。
目前對象數據庫最大的障礙是缺乏統一的規范,各個(gè)數據庫廠(chǎng)商有各自的訪(fǎng)問(wèn)接口。對象數據庫比起關(guān)系數據庫來(lái),不只是基本的幾種數據類(lèi)型那么簡(jiǎn)單,它還涉及繼承處理、多態(tài)等一大堆面向對象特征的實(shí)現,規范化道路當然困難重重。這也是對象數據庫無(wú)法普及的一個(gè)重要原因。
也有一些機構提出了一些建議的規范,比如制定Corba標準的OMG小組的一個(gè)分組ODMG提出的ODMG規范,目前已經(jīng)是3.0版本,其中的OQL對象查詢(xún)語(yǔ)言相當具有吸引力。還有一些中立的機構提出了其它的一些標準化的對象訪(fǎng)問(wèn)API,也可算是面向對象數據庫的規范之一。象前面提到的FastObjects和Ozone就是符合ODMG3.0規范的。
話(huà)說(shuō)回來(lái),在一般的開(kāi)發(fā)人員眼中,數據庫就是指關(guān)系數據庫,因此,很多應用還是采用簡(jiǎn)單的JDBC來(lái)訪(fǎng)問(wèn)數據庫。在開(kāi)發(fā)的過(guò)程中,大家逐漸感覺(jué)到JDBC的局限性,比如調用復雜、容易產(chǎn)生資源泄漏等等,與面向對象的Java語(yǔ)言有一段距離,因此,很多開(kāi)發(fā)小組開(kāi)始思考如何將應用中的數據進(jìn)行對象化建模,然后再想辦法與JDBC結合起來(lái),這就是Java數據庫開(kāi)發(fā)中的層出不窮的對象包裝技術(shù)。
傳統包裝顧名思義,就是最初出現的包裝方式,很多公司都經(jīng)歷過(guò)這一步,產(chǎn)生了很多風(fēng)格各異的包裝方法。當然,筆者也有過(guò)還算豐富的嘗試過(guò)程。
舉例來(lái)說(shuō),如果我們有一個(gè)用戶(hù)類(lèi):
public class User {
public int userId;
public String name;
public java.util.Date birthday;
}
我們可以將其當作一個(gè)簡(jiǎn)單的數據類(lèi),然后寫(xiě)一些工具方法來(lái)實(shí)現與JDBC的交互。這些方法,我們可以放到一個(gè)另外的工具類(lèi)中,也可以放到User類(lèi)中作為靜態(tài)方法。這些方法包括簡(jiǎn)單的增、刪、改、查(以Oracle為例):
public class User {
public int userId;
public String name;
public java.util.Date birthday;
public static User addUser(String name, Date birthday) throws SQLException {
Connection conn = …; //獲取一個(gè)JDBC連接
PreparedStatement ps = conn.prepareStatement("…"); // 獲取一個(gè)序列值來(lái)作為用戶(hù)標識
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.userId = rs.getInt(1); //讀取序列值為新用戶(hù)標識
user.name = name;
user.birthday = birthday;
ps = conn.prepareStatement("insert into …."); //插入用戶(hù)數據記錄的SQL
ps.setInt(1,user.id);
ps.setString(2,user.name);
ps.setDate(3,user.birthday);
ps.executeUpdate();
rs.close();
ps.close();
conn.close();
return user;
}
public static void deleteUser(int userId) throws SQLException {
Connection conn = ….;
//…
}
public static User getById(int userId) throws SQLException {
//…
}
//…
}
以上就是一個(gè)簡(jiǎn)單的數據包裝的基本雛形,我們可以看到,這是一個(gè)非常簡(jiǎn)單的JDBC包裝,一些代碼可以模塊化,以實(shí)現重用。另外,這段代碼還有很大隱患,就是中途如果出現異常的話(huà),就會(huì )使系統出現JDBC資源漏洞,因為JDBC分配的資源(conn,ps,rs等)是不能被Java虛擬機的垃圾回收機制回收的。因此,我們的addUser方法就需要改成下面的樣子:
public static User addUser(String name, Date birthday) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = new User();
try {
conn = …; //獲取一個(gè)JDBC連接
ps = conn.prepareStatement("…"); // 獲取一個(gè)序列值來(lái)作為用戶(hù)標識
rs = ps.executeQuery();
rs.next();
user.userId = rs.getInt(1); //讀取序列值為新用戶(hù)標識
user.name = name;
user.birthday = birthday;
ps = conn.prepareStatement("insert into …."); //插入用戶(hù)數據記錄的SQL
ps.setInt(1,user.id);
ps.setString(2,user.name);
ps.setDate(3,user.birthday);
ps.executeUpdate();
} finally {
//這里注意一定要按照創(chuàng )建的順序關(guān)閉JDBC資源:
if(rs != null) try { rs.close(); } catch(SQLException ex) { ex.printStackTrace(); }
if(ps != null) try { ps.close(); } catch(SQLException ex) { ex.printStackTrace(); }
if(conn != null) try { conn.close(); } catch(SQLException ex) { ex.printStackTrace(); }
}
return user;
}
所有的數據庫訪(fǎng)問(wèn)方法都必須進(jìn)行這樣的包裝,當我們的數據類(lèi)達到一定的數量后(比如十幾個(gè),幾十個(gè)),這些方法占據了大量的代碼,維護困難、出現BUG機會(huì )增多,并且不易排錯,尤其是資源漏洞這種容易引起服務(wù)器穩定性問(wèn)題的BUG。
為了保持數據類(lèi)的純潔,我們可以將JDBC操作方法集中到一個(gè)公共工具類(lèi)中去完成,這樣,這個(gè)工具類(lèi)會(huì )非常龐大,但每個(gè)數據類(lèi)會(huì )變得很簡(jiǎn)單,這種方式,可以稱(chēng)作是DataAccessObject模式,相當于EJB中的ValueObject,是脫離數據庫細節的純對象模型。
這些都是最基本的存儲處理,在基本增刪改查(這里的查指按關(guān)鍵字查找對象)的基礎上,我們還需要進(jìn)行復雜的匹配查詢(xún)(SQL),這使得我們的存儲處理代碼進(jìn)一步復雜化。簡(jiǎn)單地,我們可以寫(xiě)一個(gè)類(lèi)似的方法:
public static Collection findBy(String sql) throws SQLException {
//… (這里獲取JDBC連接)
Collection col = new Vector();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()) {
User user = new User();
user.userId = rs.getInt(1);
user.name = rs.getString(2);
user.birthday = rs.getDate(3);
col.add(user);
}
return col;
//… (同前,這里是清理JDBC資源的代碼)
}
這就是一個(gè)查詢(xún)接口的基本定義,查詢(xún)采用的語(yǔ)言仍是SQL。
如果我們需要將參數從SQL串中獨立出來(lái)以節省數據庫的解析時(shí)間并規范化,我們還需要將查詢(xún)條件作為參數傳遞到這個(gè)方法中去,方法的接口改為:
public static Collection findBy(String sql, Object[] params) throws SQLException {
//…
ps = conn.prepareStatement(sql);
for(int i = 0; i < params.length; i++) ps.setObject(i+1,params[i]);
//…
}
調用的時(shí)候sql參數中會(huì )包含一些"?"號,如:
select ID,NAME,BIRTHDAY from USER where … = ? and … > ? and …
當然,也有一些開(kāi)發(fā)團隊喜歡將所有可能的查詢(xún)都寫(xiě)死成一個(gè)個(gè)的專(zhuān)用查詢(xún)方法,在其中完成對應的SQL操作,這一點(diǎn)類(lèi)似于EJBQL,只不過(guò)是將EJBQL中容器實(shí)現的功能通過(guò)手工編碼來(lái)實(shí)現。這樣做使得查詢(xún)受到限制,但可以提供更保險的接口。
還有一些開(kāi)發(fā)人員看到每個(gè)類(lèi)中寫(xiě)這樣一些查詢(xún)方法使得這個(gè)類(lèi)的代碼變得龐大,維護麻煩,便將所有的查詢(xún)方法放到一個(gè)公共的工具類(lèi)中去,只是在方法中再加入一個(gè)參數:Class cls來(lái)表示需要查詢(xún)哪個(gè)對象,使得每個(gè)數據類(lèi)變得緊湊一些。當然,這樣的結果是那個(gè)公共類(lèi)變得異常龐大,誰(shuí)維護誰(shuí)倒霉,可以說(shuō)是犧牲一人,幸福團隊。不過(guò)如果這個(gè)人心理素質(zhì)不夠好、壓力承受能力不強的話(huà),一些對數據類(lèi)的改動(dòng)可能會(huì )受到他的阻礙,這時(shí)候就是"一夫當關(guān),萬(wàn)夫莫開(kāi)"。
現在,我們已經(jīng)實(shí)現了基本對象的包裝,現在才能開(kāi)始考慮更多的問(wèn)題。首先,我們可能會(huì )從規范化的角度出發(fā),給每一個(gè)屬性加上讀寫(xiě)訪(fǎng)問(wèn)器getter/setter,在前面的User類(lèi)中,可能我們會(huì )將基本屬性部分寫(xiě)為:
public class User {
private int userId;
private String name;
private Date birthday;
//以下是針對以上屬性的getter/setter,一般可以用IDE工具生成
public int getUserId() { return userId; }
public void setUserId(int value) { userId = value; }
public String getName() { return name; }
public void setName(String value) { name = value; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date value) { birthday = value};
//…
}
這樣,一個(gè)比較規范的數據類(lèi)包裝就算完成了。
另外,我們知道,面向對象概念中,一個(gè)屬性可以是另一個(gè)對象,也就是說(shuō),對象之間是存在著(zhù)引用關(guān)系的,這種關(guān)系還分為一對一、一對多、多對多等幾種情況。從一個(gè)既定對象出發(fā),其某個(gè)屬性可以是另一個(gè)對象,也可以是包含另一組對象的集合。那么,在我們的數據包裝里面,當然最好也能方便地處理對象之間的關(guān)系。假定現在我們又有一個(gè)數據類(lèi)Group:
public class Group {
public int grouId;
public String groupName;
public Set users; //set of User
}
這里為了簡(jiǎn)單表明含義,暫不采用getter/setter。
而User對所屬的Group有一個(gè)引用:
public Group belongTo;
在這里,User.belongTo和Group.users就是一個(gè)一對多的關(guān)系。
在我們的數據類(lèi)中,如何才能實(shí)現數據庫的存取呢?就算是不考慮Group.users這個(gè)反向關(guān)系,光是User.belongTo就是一件頭疼的事。如果我們在取出一個(gè)User對象時(shí)同時(shí)將其Group對象也取出來(lái),可以保證不會(huì )在訪(fǎng)問(wèn)某個(gè)用戶(hù)的組時(shí)得到一個(gè)null。不過(guò)這樣有幾個(gè)缺點(diǎn):
1. 數據類(lèi)的存取處理(JDBC)變得復雜,需要執行很多SQL讀取才行,有時(shí)候只需要訪(fǎng)問(wèn)User的基本屬性時(shí)浪費時(shí)間和資源;尤其是對集合型屬性的預讀取,更加可怕
2. 如果按這個(gè)邏輯,雙向的關(guān)系處理變得危險,很容易陷入死循環(huán),如果要避免,必須在類(lèi)代碼中加入一些特別的機制,也是很麻煩的事
3. 如果對象之間的關(guān)系是更復雜的情況下,比如三個(gè)、四個(gè)對象之間互相關(guān)聯(lián),那就是一場(chǎng)噩夢(mèng),對代碼的編寫(xiě)和維護都異常艱難
于是,很多開(kāi)發(fā)人員自然而然地退后一步,在User類(lèi)中只保留一個(gè)groupId,并不保存Group對象,這樣,可以將User.belongTo屬性變成int類(lèi)型,而另外寫(xiě)一個(gè)getter方法:
public Group getBelongTo() {
return Group.findById(belongTo);
}
而在Group類(lèi)中,干脆將users屬性去掉,只保留一個(gè)方法:
public Set getUsers() {
return new HashSet(User.findBy("select … from USER where BELONG_TO=?",new Object[]{ new Integer(groupId) }));
}
也許細心一點(diǎn)的讀者已經(jīng)看出來(lái)了,這里的幾個(gè)方法都沒(méi)有將SQLException捕捉,也沒(méi)有在方法中聲明,也就是說(shuō)是有語(yǔ)法錯誤的,因為SQLException不是一個(gè)RuntimeException。不錯,確實(shí)是這樣,不過(guò)我們這里為了簡(jiǎn)單明了起見(jiàn),省掉這些處理,以更直接清楚地表達意思。
這樣,實(shí)際上,我們的對象關(guān)系包裝已經(jīng)名存實(shí)亡,在類(lèi)的內部有很多用于訪(fǎng)問(wèn)所引用對象的復雜代碼,這些已經(jīng)違背了我們將對象關(guān)系保持的初衷。有些開(kāi)發(fā)人員甚至不在類(lèi)中保留訪(fǎng)問(wèn)關(guān)系對象的方法,而是在客戶(hù)調用時(shí)再去訪(fǎng)問(wèn)另一對象類(lèi)的讀取方法,如:
…
User user = User.getById(…);
//對user對象進(jìn)行一些訪(fǎng)問(wèn),如顯示其姓名等等
Group group = Group.findById(user.belongTo);
//對group對象進(jìn)行一些訪(fǎng)問(wèn),如顯示組名等等
…
在這樣的代碼里,實(shí)際上我們已經(jīng)從根本上退回了關(guān)系數據庫的出發(fā)點(diǎn),這與直接訪(fǎng)問(wèn)數據表有多大區別呢?只不過(guò)是在表上面套了一層貌似面向對象的皮而已。不幸的是,這種方式還存在于很多應用之中。
從前面提到的這些面向對象包裝的細節問(wèn)題,我們可以看到這種傳統包裝方式的一些主要的缺陷:
很多時(shí)候,我們興致勃勃地設計好一個(gè)類(lèi)圖,并且經(jīng)過(guò)評審之后,開(kāi)始對它進(jìn)行數據庫包裝,這時(shí)候,發(fā)現有些屬性名在具體的數據庫中與該數據庫的關(guān)鍵字沖突,不能用作表名或字段名,必須在數據表設計時(shí)采用另外的名稱(chēng),或者很麻煩地加上引號來(lái)使用。于是,寫(xiě)數據庫處理代碼的人有意見(jiàn)了,他必須很清楚地記得一個(gè)屬性在類(lèi)中是什么屬性名,在表中又是什么字段名,在編寫(xiě)的類(lèi)逐漸增多后,尤其是一個(gè)類(lèi)經(jīng)過(guò)歷次變動(dòng)之后,或者經(jīng)過(guò)很長(cháng)時(shí)間又需要改動(dòng),并去處理這些JDBC代碼時(shí),代碼維護人員簡(jiǎn)單要發(fā)瘋了!
這一點(diǎn)也是這種簡(jiǎn)單的包裝方法最不能擺脫關(guān)系數據庫的地方。上面也已經(jīng)說(shuō)過(guò),一些命名沖突帶來(lái)了很多維護工作量,代碼中必須還保留數據表的命名體系,而不是對象類(lèi)的命名體系。這將使調用人員仍需要清楚記得兩套命名體系,無(wú)論時(shí)間經(jīng)過(guò)多久,或者開(kāi)發(fā)人員是否有流動(dòng)。
此外,對于普遍需要用到的連表查詢(xún),也給應用開(kāi)發(fā)帶來(lái)困難,這些地方仍不能突破SQL的限制。
在處理對象集合訪(fǎng)問(wèn)或者處理集合類(lèi)型屬性時(shí),往往我們只能在同一個(gè)Connection中處理一切事務(wù),這就要求一次性地將集合中的對象全部讀入,如果集合很大的話(huà),容易造成數據庫擁塞,使得性能大打折扣,適得其反。這方面的優(yōu)化也是很多開(kāi)發(fā)人員一直在努力改進(jìn)的。
前面提過(guò),對象之間的關(guān)系處理上,普通的包裝技術(shù)是一種表面上的處理,在訪(fǎng)問(wèn)時(shí)調用者仍需要用大量的代碼進(jìn)行處理,并且,這還只是讀取,在寫(xiě)入關(guān)系屬性時(shí)會(huì )有更多的細節問(wèn)題需要處理。
面向對象的包裝到前面所說(shuō)的為止,都還只是很基本的處理,而面向對象的精華:繼承和多態(tài),在這里得不到任何幫助。我們放棄了很多合理的設計來(lái)遷就數據庫的包裝。
以上就是基本數據包裝的主要缺陷,還有更多的小問(wèn)題也需要額外的處理。
不過(guò),有責任心的開(kāi)發(fā)人員當然不會(huì )就此善罷甘休,他們冥思苦想,可能會(huì )用更好的方式來(lái)實(shí)現對象之間關(guān)系的處理,而且還會(huì )加入一些延遲訪(fǎng)問(wèn)的機制,將對象之間的引用在需要用的時(shí)候才去連接數據庫取數據,另外,在類(lèi)的繼承上,他們也試圖去在數據庫包裝上得到體現。
值得感謝的是,一些富有經(jīng)驗的團隊在經(jīng)歷若干改進(jìn)之后,毫不吝惜將他們的成果貢獻出來(lái),并將其獨立化,成為可復用的組件。這也就是后來(lái)出現的對象包裝產(chǎn)品,包括商用的和免費的。
面向對象的包裝產(chǎn)品化后,逐步推廣開(kāi)來(lái),稱(chēng)作關(guān)系/對象映射:O/R Mapping。并且,在產(chǎn)品化的過(guò)程中,產(chǎn)品提供者在產(chǎn)品中逐漸提供了更多的功能。先是一些自動(dòng)命名轉換器得以應用,將客戶(hù)代碼中的類(lèi)名、屬性名在內部處理的時(shí)候自動(dòng)地轉換到對應的數據庫結構命名空間上,這樣,應用開(kāi)發(fā)的時(shí)候不再關(guān)心具體的數據庫結構,不再需要記憶不同地命名體系,只需要一心一意地根據類(lèi)圖來(lái)進(jìn)行開(kāi)發(fā)。在此之后,這些O/R Mapping產(chǎn)品的開(kāi)發(fā)團隊又向前邁了一大步:引入了詞法分析器,提供面向對象的查詢(xún)語(yǔ)言!很多對象關(guān)系的查詢(xún)使應用開(kāi)發(fā)變得非常方便,使O/R Mapping產(chǎn)品上了一個(gè)新的臺階。
TopLink是一個(gè)非常早期的產(chǎn)品,最初面向C++,后來(lái)也實(shí)現了Java的映射。TopLink性能優(yōu)異,功能強大,并且提供了獨特的查詢(xún)過(guò)濾器機制,以及對關(guān)系的處理和查詢(xún)都非常有效,于是,TopLink逐漸從商用化O/R Mapping產(chǎn)品中勝出,成為市場(chǎng)上的最出色的映射產(chǎn)品。也正因為這一點(diǎn),最大的關(guān)系數據庫廠(chǎng)商O(píng)racle將其收購,成為提供最強數據庫和最強對象映射中間件的廠(chǎng)商。
TopLink雖然強大,但太強大的東西免不了得意忘形,TopLink開(kāi)始將用戶(hù)鎖死到自己的產(chǎn)品上,查詢(xún)方式是最突出的。它的查詢(xún)體系含有很多別扭的概念(在我看來(lái)是如此),但為達到一般O/R產(chǎn)品不能達到的功能,開(kāi)發(fā)者只能接受這些。慢慢地,也產(chǎn)生積怨,再加上其高昂的價(jià)格,讓很多新老用戶(hù)望而卻步。于是,免費的產(chǎn)品開(kāi)始崛起。
免費的O/R Mapping工具有很多種,這里只提其中最有影響力的兩種:Castor和Hibernate。
Castor是Exolab組織開(kāi)發(fā)的面向Java的包裝工具,它最大的特色就是實(shí)現了大部分的ODMG OQL規范,在查詢(xún)上,可以象完全使用一個(gè)對象數據庫一樣類(lèi)圖進(jìn)行查詢(xún)(后面會(huì )有介紹)。它的原理是通過(guò)Java反射API去實(shí)現屬性的設置和讀取。不過(guò)由于各種原因,Castor后來(lái)的版本更新越來(lái)越慢,最終停步在1.0之前,成為至今未出到1.0正式版的O/R Mapping產(chǎn)品。不管怎么樣,它還是一個(gè)相當不錯的產(chǎn)品。
Hibernate是一個(gè)現在很火熱的O/R Mapping產(chǎn)品,目前已經(jīng)出到2.0版,它功能一樣強大,同樣使用Java反射API進(jìn)行對象的設置,但它的查詢(xún)語(yǔ)言就是一套比較獨特的體系,這一點(diǎn)有點(diǎn)類(lèi)似TopLink,但Hibernate更具有親和力,對關(guān)系的查詢(xún)更方便,只不過(guò)比起Castor來(lái),在方便性和規范性上還是稍遜一籌。就目前狀況而言,Hibernate的用戶(hù)量和技術(shù)支持要強一些。
在對數據庫進(jìn)行面向對象研究的過(guò)程中,軟件世界的開(kāi)發(fā)人員和設計人員們發(fā)現:對數據庫能夠進(jìn)行對象化的查詢(xún),才是對數據庫進(jìn)行徹底的面向對象化。這體現在我們使用一種全新的數據庫查詢(xún)語(yǔ)言,能夠很簡(jiǎn)潔易懂地對數據庫中的對象進(jìn)行查詢(xún)。一個(gè)典型的例子如下:
假設我們已經(jīng)有前面提到的兩個(gè)數據類(lèi):User和Group,它們之間有一對多的關(guān)系:User.belongTo和Group.users。在數據庫中已經(jīng)存在很多這兩個(gè)類(lèi)的實(shí)例,以及相互之間的關(guān)系。我們可以使用下面的對象式查詢(xún)語(yǔ)言來(lái)查詢(xún)符合條件的User對象:
select * from User where User.belongTo.name=‘GROUP1‘
或者
select userId,name from User where User.belongTo.name=‘GROUP2‘
等等。從中我們可以看出,通過(guò)使用面向對象中的成員屬性指定符".",可以讓我們達到SQL中的連表的效果,實(shí)際上,第一個(gè)句查詢(xún)的SQL等價(jià)版本是:
select a.* from USER a, GROUP b
where a.BELONG_TO = b.GROUP_ID
and b.NAME = ‘GROUP1‘
由此可見(jiàn),對象式的查詢(xún)語(yǔ)言,比起實(shí)現同樣功能的SQL語(yǔ)言來(lái)說(shuō),簡(jiǎn)單了很多,意義也更明確,更符合使用者的思維習慣。在類(lèi)圖比較復雜、查詢(xún)涉及的類(lèi)又比較多的時(shí)候,這種新型的查詢(xún)語(yǔ)言體現出絕對的優(yōu)勢。
在面向對象式查詢(xún)語(yǔ)言的研究過(guò)程中,開(kāi)發(fā)人員們逐漸實(shí)現了相似的查詢(xún)語(yǔ)言,然后互想取長(cháng)補短,最終在ODMG組織(www.odmg.org)的統一下,形成了規范化的語(yǔ)言:ODMG OQL,這是一種完全面向對象的數據庫查詢(xún)語(yǔ)言,語(yǔ)法與前面提到的類(lèi)似,不過(guò)考慮了更廣泛的情況,語(yǔ)句更加簡(jiǎn)潔而嚴謹。
OQL并不是針對某種語(yǔ)言的,它可以被應用到很多種開(kāi)發(fā)語(yǔ)言中,它不象SQL那樣只是純字符串式的查詢(xún)語(yǔ)句,因為面向對象查詢(xún)中還必須提供相關(guān)類(lèi)的信息,所以OQL需要在編程語(yǔ)言中實(shí)現一些特定的API。
目前,ODMG的OQL已經(jīng)被規范化地應用到SmallTalk、Java、C++這些面向對象的程序設計語(yǔ)言當中,在ODMG的規范中,這幾個(gè)模塊被稱(chēng)作SmallTalk Binding、Java Binding和C++ Binding。
不過(guò),由于歷史原因,ODMG并沒(méi)有象想象中地那樣得到廣泛應用,現有的十幾個(gè)面向對象數據庫中,采用ODMG OQL規范的少之又少,目前也只有FastObjeccts、Ozone這些產(chǎn)品采納了這個(gè)規范,而象Versant這樣的大廠(chǎng)商還沒(méi)有采取OQL來(lái)查詢(xún)數據庫,而是自己定義了自己的一套API,稱(chēng)作VQL(Versant Query Lanaguage)。
在JDO之前的O/R Mapping產(chǎn)品中,也有一些產(chǎn)品使用OQL(有時(shí)候是其子集),比如Castor、Apache的Jakarta小組開(kāi)發(fā)的OJB等等。
軟件世界是一個(gè)多姿多彩的世界,總有那么一些好事之士不斷地冒出新奇的想法。還有一些開(kāi)發(fā)面向對象數據庫的組織制定了自己的一套對象式數據庫查詢(xún)語(yǔ)言,自己的規范。
不過(guò)這些規范相對來(lái)說(shuō),影響力小得多。比起ODMG來(lái),可以說(shuō)應用范圍太小,更不用說(shuō)與SQL這樣廣泛應用的標準進(jìn)行比較了。
Sun為了使Java應用在企業(yè)級數據庫應用中,不遺余力地推廣J2EE,在2001年的時(shí)候,推出了EJB2.0規范,其中包含了富有特色的面向CMP方式的EntityBean的查詢(xún)語(yǔ)言:EJBQL,功能類(lèi)似于ODMG OQL,只不過(guò)只能在EJB發(fā)布時(shí)靜態(tài)地存在于應用描述符中,不能在程序中動(dòng)態(tài)地使用。這是EJBQL最大的弱點(diǎn),也許EJB3.0規范會(huì )將其動(dòng)態(tài)化,但到了那一天,世界多半已經(jīng)不是現在的樣子了。
JDO中有最近規定的一個(gè)對象式查詢(xún)語(yǔ)言規范,稱(chēng)作JDOQL,比起OQL來(lái),JDOQL將查詢(xún)語(yǔ)言中的很多元素與Java語(yǔ)言緊密地結合在一起,有的人覺(jué)得麻煩,有些人覺(jué)得規范,評論各不相同。從筆者個(gè)人的角度來(lái)看,這樣有利于沒(méi)寫(xiě)過(guò)數據庫應用、沒(méi)用過(guò)SQL的新手很快地習慣JDOQL,但實(shí)際上,有多少人會(huì )在沒(méi)寫(xiě)過(guò)SQL,沒(méi)了解過(guò)關(guān)系數據庫的情況下去用JDO寫(xiě)數據庫應用呢?畢竟市場(chǎng)說(shuō)明了一切。個(gè)人認為,JDO中對數據庫對象的查詢(xún)多少顯得有些累贅,如果能更簡(jiǎn)化一點(diǎn),那將更吸引使用傳統SQL的開(kāi)發(fā)人員。
說(shuō)起JDO,其來(lái)由還有一段特殊的背景。Java語(yǔ)言在JDK1.1達到比較實(shí)用的目的后,企業(yè)級數據庫應用也正是軟件開(kāi)發(fā)市場(chǎng)中的重要組成部分,Sun看到這一點(diǎn)后,也希望通過(guò)Java這個(gè)強大的武器在數據庫開(kāi)發(fā)市場(chǎng)攻占市場(chǎng)份額。JDK1.2推出后,Sun同時(shí)推出了面向企業(yè)應用的EJB,對基于java的中間件服務(wù)器框架進(jìn)行了規范化定義,這就是J2EE。不過(guò)在JDK1.2時(shí),Java的速度還是不能與傳統的C/C++和Delphi這樣一些應用開(kāi)發(fā)語(yǔ)言相比。為了防止業(yè)界對Java的激情因此而消退,Sun宣布將在JDK中加入強大的虛擬機技術(shù)HotSpot,其中包含更先進(jìn)的垃圾收集算法和更優(yōu)化的Java字節代碼再編譯技術(shù)(相當于JIT,Java即時(shí)編譯技術(shù))。HotSpot引起了Java關(guān)注者的極大興趣,但Sun的HotSpot一拖再拖,最后包含在JDK1.3中出來(lái)時(shí),性能也沒(méi)有象預期的那樣好,比起C++編譯生成的代碼來(lái)還是有一段距離。
這個(gè)時(shí)候,大家開(kāi)始對Sun心存懷疑,而Sun深知這一點(diǎn),于是將公眾的注意力趕緊轉移到EJB上,從EJB1.0到EJB1.1,再到EJB2.0,業(yè)界又開(kāi)始關(guān)注J2EE中間件技術(shù)上來(lái)。很快,開(kāi)發(fā)人同發(fā)現用EJB來(lái)編寫(xiě)數據庫應用還是有很大的難度,雖然在分布式技術(shù)上EJB確實(shí)有很大的價(jià)值。在這個(gè)時(shí)候,Sun決定推出JDO技術(shù)作為輕量級的Java數據庫訪(fǎng)問(wèn)規范,而這一點(diǎn)也受到很多傳統O/R Mapping市場(chǎng)的歡迎。為了與傳統O/R Mapping有所區別,Sun一開(kāi)始就高姿態(tài)地將JDO定位成不只是面向關(guān)系數據庫的Java規范,而是針對所有的存儲技術(shù),包括面向對象數據庫和其它類(lèi)型的存儲體系(如文件),就象EJB EntityBean一樣,雖然。就筆者的角度,這個(gè)做法使第一版的JDO拋棄了很多傳統O/R Mapping提供的面向關(guān)系數據庫的功能,可以算是一個(gè)失策。
JDO最早是由Sun召集眾多的O/R Mapping開(kāi)發(fā)團隊集中起來(lái)共同提出的,首先是通過(guò)會(huì )議確定了JDO需要包括的內容,然后正式提出一個(gè)Java規范請求(JSR-12),正式開(kāi)始了JDO規范的制定。下面是主要的進(jìn)展里程碑。
JSR #000012 approved in July 1999
1999-8組建的專(zhuān)家小組:包括Sun、Apple、BEA、IBM、Oracle、SAP、WebGain等
2000-5 完成公開(kāi)評論草案
2000-6 在JavaOne上引入
2001-3 最終草案0.93
2001-5 最終草案0.96公布
2001-6 在JavaOne上啟動(dòng)
2001-11 最終草案0.98
2002-4 1.0版正式公布
2002-8 1.0.1修正版
2003-8 2.0規范啟動(dòng)
…
作為JDO專(zhuān)家組的重要成員,同時(shí)作為最大的關(guān)系數據庫廠(chǎng)商的Oracle地位顯然非同一般。在JDO規范中,Oracle也可說(shuō)是立下汗馬功勞,很多API的形成,Oracle都提供了很重要的參考意見(jiàn),最終的投票Oracle也是毫不猶豫。
可是,世間的事總是變化莫測的,就在JDO1.0快出臺之時(shí),Oracle收購了TopLink,這一點(diǎn)使Oracle的身份變得特殊而復雜。TopLink是一個(gè)商業(yè)產(chǎn)品,是以商業(yè)利益為目標的,而Oracle也是追求利益最大化的典型商家,這一點(diǎn)與JDO的開(kāi)放精神背道而馳。因此,我們看到后期Oracle對JDO的不積極態(tài)度,甚至在前一陣的JavaOne大會(huì )上有人從Oracle的角度非正式地攻擊JDO。
在JDO規范制定的同時(shí),出現了幾個(gè)主要的JDO產(chǎn)品,有美國的基于對象數據庫的FastObjects j1、法國的支持Versant對象數據庫、文件數據庫、主流RDBMS的LiDO、南非的JDOGenie、德國的JRelay等等,這些都是很不錯的JDO產(chǎn)品。下面列舉一下我對主要的幾個(gè)產(chǎn)品的印象:
LiDO(法國LibeLis公司)
我對JDO的認識主要是通過(guò)LiDO這個(gè)產(chǎn)品,它在2002年3月的一份圖文并茂的教程中簡(jiǎn)要解說(shuō)了JDO的使用和優(yōu)點(diǎn)。這個(gè)教程可以在這里下載:http://www.objectweb.org/conference/JDO.pdf。LiDO的特色是大而全,支持文件型數據庫、RDBMS、ODBMS,甚至是XML數據庫。不過(guò)配置較麻煩。最新版本是2.0RC。
KodoJDO(美國SolarMetrics公司)
Kodo是JDO的中流砥柱之一,在JDO1.0還未最后通過(guò)的時(shí)候,它就是一個(gè)比較成熟的產(chǎn)品了,其特點(diǎn)是注重性能和穩定性,目前最新版本是2.5.0,是客戶(hù)最多的產(chǎn)品。
JDOGenie(南非HemSphere公司)
這是目前我最推薦的產(chǎn)品,最新版本是1.4.7,性能也不錯,穩定性還有待驗證,但它有一個(gè)最大的特點(diǎn):集成性好,最易學(xué),其公司的CTO David Tinker也是一個(gè)善解人意的年輕人,采納了很多網(wǎng)友的意見(jiàn)對產(chǎn)品進(jìn)行改進(jìn),主要是在配置上非常方便,有一個(gè)專(zhuān)門(mén)的圖形界面工具,可以進(jìn)行配置、數據庫生成、對象查詢(xún)等等很實(shí)用的功能。
JRelay(德國ObjectIndustries公司)
這也是一個(gè)出現得比較早的產(chǎn)品,也有一個(gè)GUI工具用于配置,曾幾何時(shí),這個(gè)工具還是相對很方便的,但一年多過(guò)去了,好象沒(méi)什么進(jìn)展,最新版本是2.0,我試過(guò)一段時(shí)間,后來(lái)就沒(méi)有再跟進(jìn)了。
FrontierSuite for JDO (美國ObjectFrontier)
這個(gè)產(chǎn)品與JRelay、Kodo一起,可算是早期的JDO三個(gè)主要產(chǎn)品,它支持正向開(kāi)發(fā)和反向開(kāi)發(fā)(Reverse Engineer)。它的特色是反向工程(從表結構生成數據類(lèi))比較方便,與UML的結合也很強,不過(guò)真正運行起來(lái)的時(shí)候,配置復雜。
TJDO(一群跨國界的有志之士)
這是一個(gè)在Sun提供的參考產(chǎn)品(Reference Implementation)的基礎上加入一些擴展功能而形成的一個(gè)免費產(chǎn)品,目前最新版本是2.0beta3,不過(guò)進(jìn)展也緩慢,這個(gè)版本已經(jīng)出現好幾個(gè)月了沒(méi)有進(jìn)一步的更新。
從2002年4月JDO1.0規范正式公布以來(lái),各個(gè)產(chǎn)品層出不窮,從商業(yè)到免費的層次,都有不錯的產(chǎn)品推出。象Kodo、Lido、JDOGenie等產(chǎn)品都已經(jīng)比較成熟,可以考慮投入開(kāi)發(fā)使用。在2002年8月,JDO又推出1.0.1修正版,修正了1.0版規范中的一些文字錯誤,以及輕微地改進(jìn)了部分異常定義,不過(guò)改動(dòng)都不大。從現在的情形來(lái)看,除了Kodo有一些大學(xué)的項目用到外,好象還沒(méi)看到多少使用JDO作開(kāi)發(fā)的應用。
JDO畢竟是一個(gè)新技術(shù),從概念上到實(shí)際應用上對其掌握的用戶(hù)還不多,而這些產(chǎn)品在配置、使用上的方便性易用性還有待大幅度改進(jìn),因此,真正用JDO來(lái)開(kāi)發(fā)項目的用戶(hù)還廖廖無(wú)幾,至少我還不知道有哪些項目使用了JDO。我自己也嘗試使用JDO來(lái)開(kāi)發(fā)項目,但由于一些JDO1.0版本中還不夠完善的一些硬傷(比如不支持關(guān)系數據庫統計功能),使我對JDO仍處于觀(guān)望階段。
在八月中旬進(jìn)行的JDO2.0規劃會(huì )議中,來(lái)自各國的各個(gè)JDO產(chǎn)品廠(chǎng)商、JDO技術(shù)咨詢(xún)公司、JDO研究機構的代表匯聚一堂,將各自收集到的用戶(hù)對JDO2.0的需求總結起來(lái),提出一個(gè)個(gè)的新的議題,并且確定了每個(gè)議題的JDO規范撰寫(xiě)負責人,比如高級fetchGroup特性由目前實(shí)現得最好的JDOGenie的CTO David Tinker負責,關(guān)于managed-relationship特性由Kodo的產(chǎn)品總監負責,用戶(hù)要求最多的JDO對象與PersistenceManager的脫鉤/重掛鉤特性由Sun的Craig Russell親自操刀,等等。
最具有吸引力的JDO2.0議題,筆者個(gè)人認為是專(zhuān)門(mén)為關(guān)系數據庫設立的子規范JDO/R,這也是我一直以來(lái)最關(guān)心的,這將使目前JDBC的開(kāi)發(fā)將可以被JDO完全取代,并且保證開(kāi)發(fā)過(guò)程保持面向對象的特色。還有一些將一個(gè)類(lèi)映射到多個(gè)表之類(lèi)的特性也在規范化的列表上,這將有利于DBA在不影響應用開(kāi)發(fā)的前提下根據需要更改數據表結構,實(shí)現更好的性能。類(lèi)似的新特性還有很多,粗略地看,這些都規范化起來(lái)后,真不知道各個(gè)廠(chǎng)商還能做什么樣的擴展特性,也許以后廠(chǎng)商之間拼的只能是技術(shù)支持服務(wù)和產(chǎn)品性能了,當然,最后還有價(jià)格的競爭。
說(shuō)了這么多,我想大家關(guān)心的還是JDO2.0到底什么時(shí)候能出來(lái),我們什么時(shí)候可以用上它,什么時(shí)候有中文版產(chǎn)品,價(jià)格到底如何。這些問(wèn)題目前筆者還無(wú)法一一回答,只能根據筆者所掌握的信息初步解釋一下。據前幾天的JDO2.0啟動(dòng)大會(huì )上David Jordan的預期,JDO2.0正式版將在18個(gè)月后正式完成。那正式完成后廠(chǎng)商什么時(shí)候才能提供符合規范的產(chǎn)品呢?這個(gè)問(wèn)題不用擔心,因為規范在制定的過(guò)程中會(huì )不斷地公布公眾預覽版(Public Review),這樣,廠(chǎng)商可以先實(shí)現其中的功能,等規范正式完成后,也不會(huì )有太大的變化,廠(chǎng)商也不會(huì )需要太多時(shí)間來(lái)跟進(jìn)最終規范。所以,我估計一年之后,我們就可以在JDO2.0上進(jìn)行開(kāi)發(fā)了。至于價(jià)格如何,1.0規范的產(chǎn)品初步印象是每個(gè)開(kāi)發(fā)人員需要一個(gè)License,一個(gè)License大概2000美元。如果JDO2.0產(chǎn)品的價(jià)格還保持這么貴的話(huà)(至少對中國用戶(hù)來(lái)說(shuō)),我們也還有很多免費(如JPOX,TJDO)或半免費(如JCredo)產(chǎn)品可以選擇。最后一個(gè)關(guān)于中文版的問(wèn)題,有待于廠(chǎng)商對中國市場(chǎng)的考察,或者看看是否有國內的JDO產(chǎn)品了。不過(guò),在JDO2.0規范制定的同時(shí),我們可以先集眾人之力將其普及,使廣大的使用Java語(yǔ)言進(jìn)行數據庫開(kāi)發(fā)的開(kāi)發(fā)人員都來(lái)認識JDO,了解JDO,甚至將其用到項目開(kāi)發(fā)之中。
也許,JDO的目標已經(jīng)吸引了Java世界以外的人,微軟發(fā)現了這一點(diǎn),也立即計劃在.NET體系中加入一個(gè)仿照JDO的中間件,具體是采用ObjectStore的產(chǎn)品,ObjectStore是一個(gè)同時(shí)做JDO和.NET-DO(姑且使用這個(gè)名稱(chēng))的公司。
在這里,筆者可以大膽地預測,在未來(lái)的一兩年內,JDO將在Java世界大放光彩!
在2003年6月舉行的JavaOne大會(huì )上,JDO備受矚目,很多開(kāi)發(fā)者或開(kāi)發(fā)組織對其產(chǎn)生了極大的興趣,在各大網(wǎng)站媒體上也頻頻曝光,大多對其評價(jià)不錯,當然,也有一些負面的評價(jià)。
不過(guò),網(wǎng)站上的報道也不可盡信,比如服務(wù)器領(lǐng)域的權威網(wǎng)站TheServerSide.com上介紹JavaOne大會(huì )第二天關(guān)于JDO的一次會(huì )議的報道就有誤導之嫌,從報道的內容來(lái)看,好象會(huì )議用來(lái)答疑與交流的的最后五分鐘全被一個(gè)好事者占據,這個(gè)人拼命鼓吹Oracle的TopLink解決方案和一些易用性的改進(jìn),從而攻擊JDO的市場(chǎng)前景。后來(lái),我就這一信息與參加會(huì )議的JDO專(zhuān)家組的David Jordan交流時(shí),他糾正了我的錯誤理解,實(shí)際情形是:那個(gè)好事者是一個(gè)積極的JDO擁護者,他花了超過(guò)五分鐘時(shí)間向大家揭露Oracle的TopLink改進(jìn)實(shí)際上也是抄襲JDO的概念而進(jìn)行的一些API改動(dòng)!不過(guò)有一點(diǎn)是相同的,這個(gè)好事者占據了大家的提問(wèn)時(shí)間,使這次會(huì )議在意猶未盡中結束。
聯(lián)系客服